Modul 28 · Migration Deep Dive · Stufe 5 Enterprise Runtime

JPMS / Jigsaw

Classpath und globale Sichtbarkeit wird nachvollziehbar in module-info, exports und Service Provider überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.

ModuleService Provider
2 → 5Produktionsdateien
19 → 45Java-Zeilen
1 → 0Testdateien
0 / 0Dependencies entfernt / neu
MITTELRisiko · Score 4

Was sich konkret ändert

DimensionLegacyModernMigrationskonsequenz
Programmiermodellimperativ / ohne Framework-Annotationenexplizite Java-AbstraktionenAnnotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen.
Abhängigkeiten1 direkte Dependencies1 direkte Dependencies0 neu, 0 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen.
Öffentliche API2 erkannte Methoden3 erkannte MethodenMethoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag.
Datenmodellclass LegacyGreetingPlugin, class LegacyPluginLoaderclass GermanGreetingProvider, class JpmsApplication, class JpmsSmokeCheck, interface GreetingProvider, module-infoFeldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet.
FehlerverhaltenLegacy-Exceptions und Rückgabewerteexplizitere Fach-/Framework-FehlerabbildungFehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden.
TestsBestands- und Golden-Master-TestsUnit-, Slice-, Contract- und IntegrationstestsDer Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt.
BetriebLegacy-Start/Lifecyclemodernes Packaging, Health und externe KonfigurationModule Path/JAR-Inhalt und Service Discovery im finalen Artefakt testen.
RollbackLegacy-Artefakt bleibt unverändertModern-Artefakt getrennt deploybarKein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein.

Fachlicher Vertrag: unverändert zu erhalten

  • Öffentliche Pakete sind minimal und bewusst exportiert.
  • Keine Split Packages.
  • Service Provider funktionieren auf dem Module Path.

Hauptrisiko und Testfokus

split packages, exports and readability

module-path compile, forbidden access and service-loading tests

Die Modernisierung gilt erst als abgeschlossen, wenn der fachliche Vertrag automatisiert belegt ist.

Verbindliches Code- und Rollenmapping

Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.

Legacy-Rolle / DateiModern-Rolle / DateiBedeutung
LegacyPluginLoader.java + LegacyGreetingPlugin.javaGreetingProvider.java + GermanGreetingProvider.javaClasspath Plugin wird expliziter Service Provider.
globale Classpath-Sichtbarkeitmodule-info.javarequires/exports/uses/provides werden deklarativ.
Legacy StartJpmsApplication.java + JpmsSmokeCheck.javaStart und Module-Path-Smoke-Test werden explizit.

Legacy-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
LegacyGreetingPlugin.javaclass LegacyGreetingPluginString greet()7
LegacyPluginLoader.javaclass LegacyPluginLoaderObject load(String className)Plugin Loader / Factory – erzeugt Plugins dynamisch über Reflection.12

Dependency- und Laufzeitmigration

StatusDependencyVersionScopePrüfung
BEIBEHALTENorg.junit.jupiter:junit-jupiterBOM/Parent → BOM/Parenttest → testGemeinsame Dependency; Version und Scope im effektiven POM prüfen.
Direkte POM-Daten ersetzen keinen erfolgreichen Online-Build mit transitiver SBOM- und CVE-Prüfung.

Vorher-/Nachher-Codebelege

Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.

Legacy
LegacyPluginLoader.java + LegacyGreetingPlugin.java
Modern
GreetingProvider.java + GermanGreetingProvider.java

Migrationsbedeutung: Classpath Plugin wird expliziter Service Provider.

Legacy-Code

projects/28-jpms-jigsaw/legacy/src/main/java/at/aydin/lab/jpms/legacy/LegacyPluginLoader.java

package at.aydin.lab.jpms.legacy;

// Design Pattern: Plugin Loader / Factory – erzeugt Plugins dynamisch über Reflection.
public final class LegacyPluginLoader {
    public Object load(String className) {
        try {
            return Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (ReflectiveOperationException ex) {
            throw new IllegalStateException(ex);
        }
    }
}

Legacy-Code

projects/28-jpms-jigsaw/legacy/src/main/java/at/aydin/lab/jpms/legacy/LegacyGreetingPlugin.java

package at.aydin.lab.jpms.legacy;

public final class LegacyGreetingPlugin {
    public String greet() {
        return "Hallo aus dem Classpath";
    }
}

Modern-Code

projects/28-jpms-jigsaw/modern/src/main/java/at/aydin/lab/jpms/modern/api/GreetingProvider.java

package at.aydin.lab.jpms.modern.api;

// Design Pattern: Service Provider Interface
// Zweck: Consumer hängt nur von exportiertem API-Package ab.
public interface GreetingProvider {
    String greet(String name);
}

Modern-Code

projects/28-jpms-jigsaw/modern/src/main/java/at/aydin/lab/jpms/modern/internal/GermanGreetingProvider.java

package at.aydin.lab.jpms.modern.internal;

import at.aydin.lab.jpms.modern.api.GreetingProvider;

public final class GermanGreetingProvider implements GreetingProvider {
    public String greet(String name) {
        return "Hallo " + name;
    }
}
Legacy
globale Classpath-Sichtbarkeit
Modern
module-info.java

Migrationsbedeutung: requires/exports/uses/provides werden deklarativ.

Legacy-Code

projects/28-jpms-jigsaw/legacy/src/main/java/at/aydin/lab/jpms/legacy/LegacyPluginLoader.java

package at.aydin.lab.jpms.legacy;

// Design Pattern: Plugin Loader / Factory – erzeugt Plugins dynamisch über Reflection.
public final class LegacyPluginLoader {
    public Object load(String className) {
        try {
            return Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (ReflectiveOperationException ex) {
            throw new IllegalStateException(ex);
        }
    }
}

Modern-Code

projects/28-jpms-jigsaw/modern/src/main/java/at/aydin/lab/jpms/modern/JpmsSmokeCheck.java

package at.aydin.lab.jpms.modern;

import at.aydin.lab.jpms.modern.api.GreetingProvider;
import at.aydin.lab.jpms.modern.internal.GermanGreetingProvider;

public final class JpmsSmokeCheck {
    public static boolean valid() {
        return "Hallo Test".equals(new GermanGreetingProvider().greet("Test"));
    }
}
Technischen Unified Diff öffnen
--- LegacyPluginLoader.java
+++ JpmsSmokeCheck.java
@@ -1,12 +1,10 @@
-package at.aydin.lab.jpms.legacy;
+package at.aydin.lab.jpms.modern;
 
-// Design Pattern: Plugin Loader / Factory – erzeugt Plugins dynamisch über Reflection.
-public final class LegacyPluginLoader {
-    public Object load(String className) {
-        try {
-            return Class.forName(className).getDeclaredConstructor().newInstance();
-        } catch (ReflectiveOperationException ex) {
-            throw new IllegalStateException(ex);
-        }
+import at.aydin.lab.jpms.modern.api.GreetingProvider;
+import at.aydin.lab.jpms.modern.internal.GermanGreetingProvider;
+
+public final class JpmsSmokeCheck {
+    public static boolean valid() {
+        return "Hallo Test".equals(new GermanGreetingProvider().greet("Test"));
     }
 }
Legacy
Legacy Start
Modern
JpmsApplication.java + JpmsSmokeCheck.java

Migrationsbedeutung: Start und Module-Path-Smoke-Test werden explizit.

Legacy-Code

projects/28-jpms-jigsaw/legacy/src/main/java/at/aydin/lab/jpms/legacy/LegacyPluginLoader.java

package at.aydin.lab.jpms.legacy;

// Design Pattern: Plugin Loader / Factory – erzeugt Plugins dynamisch über Reflection.
public final class LegacyPluginLoader {
    public Object load(String className) {
        try {
            return Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (ReflectiveOperationException ex) {
            throw new IllegalStateException(ex);
        }
    }
}

Modern-Code

projects/28-jpms-jigsaw/modern/src/main/java/at/aydin/lab/jpms/modern/JpmsApplication.java

package at.aydin.lab.jpms.modern;

import at.aydin.lab.jpms.modern.api.GreetingProvider;
import java.util.*;

public final class JpmsApplication {
    private JpmsApplication() {
    }

    public static void main(String[] args) {
        GreetingProvider provider = ServiceLoader.load(GreetingProvider.class).findFirst().orElseThrow();
        System.out.println(provider.greet("Aydin"));
    }
}

Modern-Code

projects/28-jpms-jigsaw/modern/src/main/java/at/aydin/lab/jpms/modern/JpmsSmokeCheck.java

package at.aydin.lab.jpms.modern;

import at.aydin.lab.jpms.modern.api.GreetingProvider;
import at.aydin.lab.jpms.modern.internal.GermanGreetingProvider;

public final class JpmsSmokeCheck {
    public static boolean valid() {
        return "Hallo Test".equals(new GermanGreetingProvider().greet("Test"));
    }
}

Umsetzungsplan mit Qualitäts-Gates

  1. Arbeitspaket 1
    Abhängigkeiten und Package-Zyklen mit jdeps/Build analysieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  2. Arbeitspaket 2
    API- und Internal-Pakete trennen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  3. Arbeitspaket 3
    module-info mit requires/exports minimal erstellen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  4. Arbeitspaket 4
    Service Provider über uses/provides registrieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  5. Arbeitspaket 5
    Tests explizit auf dem Module Path ausführen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  6. Arbeitspaket 6
    Classpath-Fallback erst nach Packaging-/Starttests entfernen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.

Konkreter Test- und Abnahmekatalog

IDEbenePrüfungerforderlicher Nachweis
28-JPMS-JIGSAW-A01Integration/ContractModul kompiliert und startet auf dem Module Path.Automatisierter Test und CI-Protokoll
28-JPMS-JIGSAW-A02Integration/ContractInterne Pakete sind von außen nicht lesbar.Automatisierter Test und CI-Protokoll
28-JPMS-JIGSAW-A03Integration/ContractKeine automatischen Module mit instabilen Namen in kritischem Pfad.Automatisierter Test und CI-Protokoll
28-JPMS-JIGSAW-A04Integration/ContractServiceLoader findet Provider.Automatisierter Test und CI-Protokoll
28-JPMS-JIGSAW-A05Integration/ContractReflection-Zugriffe benötigen nur dokumentierte opens.Automatisierter Test und CI-Protokoll
28-JPMS-JIGSAW-T01UnitFachlogik ohne Container oder externen Dienst testen.Unit-Test
28-JPMS-JIGSAW-T02RegressionLegacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen.Vergleichsreport
28-JPMS-JIGSAW-T03NegativeFehlerhafte, leere und grenzwertige Eingaben prüfen.Negativtest
28-JPMS-JIGSAW-T04OperationsStart, Health, Shutdown und Konfigurationsfehler prüfen.Deployment-/Startprotokoll
28-JPMS-JIGSAW-T05PackagingModule Path, JAR-Inhalt und Service Discovery aus finalem Artefakt prüfen.Packaging-Smoke-Test
28-JPMS-JIGSAW-F01Fokusmodule-path compile, forbidden access and service-loading testsModulspezifischer Testreport

Risikoregister des Moduls

RisikoAuswirkungGegenmaßnahmeGate
split packages, exports and readabilityMITTELmodule-path compile, forbidden access and service-loading testsvor Cutover
Modern-Seite besitzt keinen TestquellcodeHOCHMindestens Unit- und Integrations-/Contract-Test ergänzenBuild blockieren

Konfiguration und Ressourcen

Keine zusätzlichen Ressourcen.

Rollback und Koexistenz

Das Artefakt kann vorübergehend weiterhin auf dem Classpath laufen, solange Package- und Serviceverträge kompatibel bleiben.

Abbruchkriterien

  • Fachlicher Golden-Master weicht ab.
  • Daten-, Nachrichten- oder API-Kompatibilität ist ungeklärt.
  • Fehlerquote, Latenz oder Ressourcenverbrauch überschreiten das vereinbarte Limit.
  • Monitoring oder Rückfallpfad ist nicht funktionsfähig.

Definition of Done

Direkte Arbeitslinks

⌂ Cockpit