Modul 14 · Migration Deep Dive · Stufe 2 Java Core

Annotations und Reflection

Namenskonventionen und Reflection-Strings wird nachvollziehbar in Annotation-gesteuertes Command Registry überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.

CommandRegistryMetadata
2 → 3Produktionsdateien
32 → 60Java-Zeilen
1 → 1Testdateien
0 / 0Dependencies entfernt / neu
NIEDRIGRisiko · Score 1

Was sich konkret ändert

DimensionLegacyModernMigrationskonsequenz
Programmiermodellimperativ / ohne Framework-AnnotationenCommand, Retention, Target, interfaceAnnotationen 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 API3 erkannte Methoden3 erkannte MethodenMethoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag.
Datenmodellclass LegacyCommandRegistry, class LegacyCommandsclass CommandRegistry, class ModernCommands, interface Command, record HandlerFeldnamen, 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 KonfigurationUmstellung über kleine Adapter und Golden-Master-Tests statt Big Bang.
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

  • Command-Namen sind eindeutig und stabil.
  • Nur explizit markierte Methoden werden registriert.
  • Reflection-Fehler führen zu klarem Startup-Fehler statt spätem Laufzeitfehler.

Hauptrisiko und Testfokus

illegal access, duplicate commands and startup failures

duplicate annotation, missing method and invocation failure 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
LegacyCommandRegistry.javaCommandRegistry.java + Command.javaString-/Konventionssuche wird explizite Metadatenregistrierung.
LegacyCommands.javaModernCommands.javaCommand-Implementierungen erhalten Annotation statt Namenskonvention.

Legacy-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
LegacyCommandRegistry.javaclass LegacyCommandRegistryString execute(String command, String argument)Registry21
LegacyCommands.javaclass LegacyCommandsString command_hello(String name)
String command_bye(String name)
11

Modern-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
Command.javainterface CommandRetention, Target, interface11
CommandRegistry.javaclass CommandRegistry, record HandlerString execute(String command, String argument)Command + Metadata Registry36
ModernCommands.javaclass ModernCommandsCommandString greet(String name)
String farewell(String name)
13

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
LegacyCommandRegistry.java
Modern
CommandRegistry.java + Command.java

Migrationsbedeutung: String-/Konventionssuche wird explizite Metadatenregistrierung.

Legacy-Code

projects/14-annotations-reflection/legacy/src/main/java/at/aydin/lab/annotations/legacy/LegacyCommandRegistry.java

package at.aydin.lab.annotations.legacy;

import java.lang.reflect.*;

// Design Pattern: Registry
// Zweck: Historische Registrierung über String-Konventionen und Reflection.
public final class LegacyCommandRegistry {
    private final Object target;
    public LegacyCommandRegistry(Object target) {
        this.target = target;
    }

    public String execute(String command, String argument) {
        try {
            Method m = target.getClass().getMethod("command_" + command, String.class);
            return (String) m.invoke(target, argument);
        } catch (ReflectiveOperationException ex) {
            throw new IllegalArgumentException("Unbekanntes Kommando: " + command, ex);
        }
    }
}

Modern-Code

projects/14-annotations-reflection/modern/src/main/java/at/aydin/lab/annotations/modern/CommandRegistry.java

package at.aydin.lab.annotations.modern;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

// Design Pattern: Command + Metadata Registry
// Zweck: Annotationen machen Namen explizit und entkoppeln sie von Methodenkonventionen.
public final class CommandRegistry {
    private record Handler(Object target, Method method) {}

    private final Map<String, Handler> handlers = new HashMap<>();

    public CommandRegistry(Object... targets) {
        for (Object target : targets) {
            for (Method method : target.getClass().getDeclaredMethods()) {
                Command command = method.getAnnotation(Command.class);
                if (command != null) {
                    handlers.put(command.value(), new Handler(target, method));
                }
            }
        }
    }

    public String execute(String command, String argument) {
        Handler handler = Optional.ofNullable(handlers.get(command))
                .orElseThrow(() -> new IllegalArgumentException(
                        "Unbekanntes Kommando: " + command));
        try {
            return (String) handler.method().invoke(handler.target(), argument);
        } catch (ReflectiveOperationException exception) {
            throw new IllegalStateException(exception);
        }
    }
}

Modern-Code

projects/14-annotations-reflection/modern/src/main/java/at/aydin/lab/annotations/modern/Command.java

package at.aydin.lab.annotations.modern;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public
@interface
Command {
    String value();
}
Legacy
LegacyCommands.java
Modern
ModernCommands.java

Migrationsbedeutung: Command-Implementierungen erhalten Annotation statt Namenskonvention.

Legacy-Code

projects/14-annotations-reflection/legacy/src/main/java/at/aydin/lab/annotations/legacy/LegacyCommands.java

package at.aydin.lab.annotations.legacy;

public final class LegacyCommands {
    public String command_hello(String name) {
        return "Hallo " + name;
    }

    public String command_bye(String name) {
        return "Tschüss " + name;
    }
}

Modern-Code

projects/14-annotations-reflection/modern/src/main/java/at/aydin/lab/annotations/modern/ModernCommands.java

package at.aydin.lab.annotations.modern;

public final class ModernCommands {
    @Command("hello")
    public String greet(String name) {
        return "Hallo " + name;
    }

    @Command("bye")
    public String farewell(String name) {
        return "Tschüss " + name;
    }
}
Technischen Unified Diff öffnen
--- LegacyCommands.java
+++ ModernCommands.java
@@ -1,11 +1,13 @@
-package at.aydin.lab.annotations.legacy;
+package at.aydin.lab.annotations.modern;
 
-public final class LegacyCommands {
-    public String command_hello(String name) {
+public final class ModernCommands {
+    @Command("hello")
+    public String greet(String name) {
         return "Hallo " + name;
     }
 
-    public String command_bye(String name) {
+    @Command("bye")
+    public String farewell(String name) {
         return "Tschüss " + name;
     }
 }

Umsetzungsplan mit Qualitäts-Gates

  1. Arbeitspaket 1
    Bisherige Namenskonvention und erlaubte Signaturen dokumentieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  2. Arbeitspaket 2
    Command-Annotation mit Runtime-Retention und Method-Target definieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  3. Arbeitspaket 3
    CommandRegistry beim Start validierend aufbauen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  4. Arbeitspaket 4
    Duplikate, falsche Signaturen und Zugriffsfehler hart ablehnen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  5. Arbeitspaket 5
    Invocation-Exceptions in stabile Fach-/Technikfehler übersetzen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  6. Arbeitspaket 6
    String-basierte Registry nach vollständiger Command-Abdeckung entfernen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.

Konkreter Test- und Abnahmekatalog

IDEbenePrüfungerforderlicher Nachweis
14-ANNOTATIONS-REFLECTION-A01Integration/ContractJeder Command ist genau einmal registriert.Automatisierter Test und CI-Protokoll
14-ANNOTATIONS-REFLECTION-A02Integration/ContractFalsche Signatur stoppt den Start mit verständlicher Meldung.Automatisierter Test und CI-Protokoll
14-ANNOTATIONS-REFLECTION-A03Integration/ContractUnbekannter Command liefert definierten Fehler.Automatisierter Test und CI-Protokoll
14-ANNOTATIONS-REFLECTION-A04Integration/ContractPrivate/unerlaubte Methoden werden nicht geöffnet.Automatisierter Test und CI-Protokoll
14-ANNOTATIONS-REFLECTION-A05Integration/ContractInvocation erhält Ursache und Kontext.Automatisierter Test und CI-Protokoll
14-ANNOTATIONS-REFLECTION-T01UnitFachlogik ohne Container oder externen Dienst testen.Unit-Test
14-ANNOTATIONS-REFLECTION-T02RegressionLegacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen.Vergleichsreport
14-ANNOTATIONS-REFLECTION-T03NegativeFehlerhafte, leere und grenzwertige Eingaben prüfen.Negativtest
14-ANNOTATIONS-REFLECTION-T04OperationsStart, Health, Shutdown und Konfigurationsfehler prüfen.Deployment-/Startprotokoll
14-ANNOTATIONS-REFLECTION-F01Fokusduplicate annotation, missing method and invocation failure testsModulspezifischer Testreport

Risikoregister des Moduls

RisikoAuswirkungGegenmaßnahmeGate
illegal access, duplicate commands and startup failuresNIEDRIGduplicate annotation, missing method and invocation failure testsvor Cutover

Konfiguration und Ressourcen

Keine zusätzlichen Ressourcen.

Rollback und Koexistenz

Die Registry kann beide Erkennungsstrategien parallel lesen, wobei Annotationen Vorrang haben und Konflikte protokolliert werden.

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