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.
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.
| Dimension | Legacy | Modern | Migrationskonsequenz |
|---|---|---|---|
| Programmiermodell | imperativ / ohne Framework-Annotationen | Command, Retention, Target, interface | Annotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen. |
| Abhängigkeiten | 1 direkte Dependencies | 1 direkte Dependencies | 0 neu, 0 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen. |
| Öffentliche API | 3 erkannte Methoden | 3 erkannte Methoden | Methoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag. |
| Datenmodell | class LegacyCommandRegistry, class LegacyCommands | class CommandRegistry, class ModernCommands, interface Command, record Handler | Feldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet. |
| Fehlerverhalten | Legacy-Exceptions und Rückgabewerte | explizitere Fach-/Framework-Fehlerabbildung | Fehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden. |
| Tests | Bestands- und Golden-Master-Tests | Unit-, Slice-, Contract- und Integrationstests | Der Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt. |
| Betrieb | Legacy-Start/Lifecycle | modernes Packaging, Health und externe Konfiguration | Umstellung über kleine Adapter und Golden-Master-Tests statt Big Bang. |
| Rollback | Legacy-Artefakt bleibt unverändert | Modern-Artefakt getrennt deploybar | Kein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein. |
illegal access, duplicate commands and startup failures
duplicate annotation, missing method and invocation failure tests
Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.
| Legacy-Rolle / Datei | Modern-Rolle / Datei | Bedeutung |
|---|---|---|
| LegacyCommandRegistry.java | CommandRegistry.java + Command.java | String-/Konventionssuche wird explizite Metadatenregistrierung. |
| LegacyCommands.java | ModernCommands.java | Command-Implementierungen erhalten Annotation statt Namenskonvention. |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| LegacyCommandRegistry.java | class LegacyCommandRegistry | — | String execute(String command, String argument) | Registry | 21 |
| LegacyCommands.java | class LegacyCommands | — | String command_hello(String name) String command_bye(String name) | — | 11 |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| Command.java | interface Command | Retention, Target, interface | — | — | 11 |
| CommandRegistry.java | class CommandRegistry, record Handler | — | String execute(String command, String argument) | Command + Metadata Registry | 36 |
| ModernCommands.java | class ModernCommands | Command | String greet(String name) String farewell(String name) | — | 13 |
| Status | Dependency | Version | Scope | Prüfung |
|---|---|---|---|---|
| BEIBEHALTEN | org.junit.jupiter:junit-jupiter | BOM/Parent → BOM/Parent | test → test | Gemeinsame Dependency; Version und Scope im effektiven POM prüfen. |
Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.
Migrationsbedeutung: String-/Konventionssuche wird explizite Metadatenregistrierung.
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);
}
}
}
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);
}
}
}
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();
}
Migrationsbedeutung: Command-Implementierungen erhalten Annotation statt Namenskonvention.
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;
}
}
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;
}
}
--- 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;
}
}
| ID | Ebene | Prüfung | erforderlicher Nachweis |
|---|---|---|---|
| 14-ANNOTATIONS-REFLECTION-A01 | Integration/Contract | Jeder Command ist genau einmal registriert. | Automatisierter Test und CI-Protokoll |
| 14-ANNOTATIONS-REFLECTION-A02 | Integration/Contract | Falsche Signatur stoppt den Start mit verständlicher Meldung. | Automatisierter Test und CI-Protokoll |
| 14-ANNOTATIONS-REFLECTION-A03 | Integration/Contract | Unbekannter Command liefert definierten Fehler. | Automatisierter Test und CI-Protokoll |
| 14-ANNOTATIONS-REFLECTION-A04 | Integration/Contract | Private/unerlaubte Methoden werden nicht geöffnet. | Automatisierter Test und CI-Protokoll |
| 14-ANNOTATIONS-REFLECTION-A05 | Integration/Contract | Invocation erhält Ursache und Kontext. | Automatisierter Test und CI-Protokoll |
| 14-ANNOTATIONS-REFLECTION-T01 | Unit | Fachlogik ohne Container oder externen Dienst testen. | Unit-Test |
| 14-ANNOTATIONS-REFLECTION-T02 | Regression | Legacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen. | Vergleichsreport |
| 14-ANNOTATIONS-REFLECTION-T03 | Negative | Fehlerhafte, leere und grenzwertige Eingaben prüfen. | Negativtest |
| 14-ANNOTATIONS-REFLECTION-T04 | Operations | Start, Health, Shutdown und Konfigurationsfehler prüfen. | Deployment-/Startprotokoll |
| 14-ANNOTATIONS-REFLECTION-F01 | Fokus | duplicate annotation, missing method and invocation failure tests | Modulspezifischer Testreport |
| Risiko | Auswirkung | Gegenmaßnahme | Gate |
|---|---|---|---|
| illegal access, duplicate commands and startup failures | NIEDRIG | duplicate annotation, missing method and invocation failure tests | vor Cutover |
Keine zusätzlichen Ressourcen.
Die Registry kann beide Erkennungsstrategien parallel lesen, wobei Annotationen Vorrang haben und Konflikte protokolliert werden.