Fachlicher Vertrag: unverändert zu erhalten
- Reihenfolge, Duplikat- und Null-Semantik sind dokumentiert.
- Aufrufer erhalten keine veränderbare interne Collection.
- Iteration bleibt deterministisch, wenn fachlich erforderlich.
Vector, Hashtable und Enumeration wird nachvollziehbar in generische Collections und unveränderliche Sichten ü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 | explizite Java-Abstraktionen | 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 | 4 erkannte Methoden | Methoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag. |
| Datenmodell | class LegacyInventory | class Inventory | 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. |
mutation leaks and ordering semantics
aliasing, null, duplicates and ordering tests
Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.
| Legacy-Rolle / Datei | Modern-Rolle / Datei | Bedeutung |
|---|---|---|
| LegacyInventory.java | Inventory.java | Legacy Collections werden generisch und defensiv gekapselt. |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| LegacyInventory.java | class LegacyInventory | — | void add(String sku, int quantity) int quantity(String sku) Vector<String> orderedSkus() | Collection Wrapper | 22 |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| Inventory.java | class Inventory | — | void add(String sku, int quantity) int quantity(String sku) Map<String, Integer> snapshot() List<String> orderedSkus() | Snapshot | 26 |
| 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: Legacy Collections werden generisch und defensiv gekapselt.
projects/12-collections/legacy/src/main/java/at/aydin/lab/collections/legacy/LegacyInventory.java
package at.aydin.lab.collections.legacy;
import java.util.*;
// Design Pattern: Collection Wrapper
// Zweck: Kapselt alte Vector-/Hashtable-Strukturen hinter fachlichen Methoden.
public final class LegacyInventory {
private final Vector<String> order = new Vector<>();
private final Hashtable<String, Integer> stock = new Hashtable<>();
public void add(String sku, int quantity) {
if (!stock.containsKey(sku)) order.add(sku);
stock.put(sku, stock.getOrDefault(sku, 0) + quantity);
}
public int quantity(String sku) {
return stock.getOrDefault(sku, 0);
}
public Vector<String> orderedSkus() {
return new Vector<>(order);
}
}
projects/12-collections/modern/src/main/java/at/aydin/lab/collections/modern/Inventory.java
package at.aydin.lab.collections.modern;
import java.util.*;
// Design Pattern: Snapshot
// Zweck: Gibt unveränderliche Momentaufnahmen statt interner mutabler Collections zurück.
public final class Inventory {
private final LinkedHashMap<String, Integer> stock = new LinkedHashMap<>();
public void add(String sku, int quantity) {
Objects.requireNonNull(sku);
if (quantity <= 0) throw new IllegalArgumentException("quantity");
stock.merge(sku, quantity, Integer::sum);
}
public int quantity(String sku) {
return stock.getOrDefault(sku, 0);
}
public Map<String, Integer> snapshot() {
return Collections.unmodifiableMap(new LinkedHashMap<>(stock));
}
public List<String> orderedSkus() {
return List.copyOf(stock.sequencedKeySet());
}
}
--- LegacyInventory.java
+++ Inventory.java
@@ -1,22 +1,26 @@
-package at.aydin.lab.collections.legacy;
+package at.aydin.lab.collections.modern;
import java.util.*;
-// Design Pattern: Collection Wrapper
-// Zweck: Kapselt alte Vector-/Hashtable-Strukturen hinter fachlichen Methoden.
-public final class LegacyInventory {
- private final Vector<String> order = new Vector<>();
- private final Hashtable<String, Integer> stock = new Hashtable<>();
+// Design Pattern: Snapshot
+// Zweck: Gibt unveränderliche Momentaufnahmen statt interner mutabler Collections zurück.
+public final class Inventory {
+ private final LinkedHashMap<String, Integer> stock = new LinkedHashMap<>();
public void add(String sku, int quantity) {
- if (!stock.containsKey(sku)) order.add(sku);
- stock.put(sku, stock.getOrDefault(sku, 0) + quantity);
+ Objects.requireNonNull(sku);
+ if (quantity <= 0) throw new IllegalArgumentException("quantity");
+ stock.merge(sku, quantity, Integer::sum);
}
public int quantity(String sku) {
return stock.getOrDefault(sku, 0);
}
- public Vector<String> orderedSkus() {
- return new Vector<>(order);
+ public Map<String, Integer> snapshot() {
+ return Collections.unmodifiableMap(new LinkedHashMap<>(stock));
+ }
+
+ public List<String> orderedSkus() {
+ return List.copyOf(stock.sequencedKeySet());
}
}
| ID | Ebene | Prüfung | erforderlicher Nachweis |
|---|---|---|---|
| 12-COLLECTIONS-A01 | Integration/Contract | Keine Raw Types oder unchecked Casts im Modern-Code. | Automatisierter Test und CI-Protokoll |
| 12-COLLECTIONS-A02 | Integration/Contract | Externe Änderungen beeinflussen internen Zustand nicht. | Automatisierter Test und CI-Protokoll |
| 12-COLLECTIONS-A03 | Integration/Contract | Reihenfolge und Duplikate entsprechen Vertrag. | Automatisierter Test und CI-Protokoll |
| 12-COLLECTIONS-A04 | Integration/Contract | Null-Verhalten ist explizit. | Automatisierter Test und CI-Protokoll |
| 12-COLLECTIONS-A05 | Integration/Contract | Nebenläufige Zugriffe sind entweder sicher oder verboten/dokumentiert. | Automatisierter Test und CI-Protokoll |
| 12-COLLECTIONS-T01 | Unit | Fachlogik ohne Container oder externen Dienst testen. | Unit-Test |
| 12-COLLECTIONS-T02 | Regression | Legacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen. | Vergleichsreport |
| 12-COLLECTIONS-T03 | Negative | Fehlerhafte, leere und grenzwertige Eingaben prüfen. | Negativtest |
| 12-COLLECTIONS-T04 | Operations | Start, Health, Shutdown und Konfigurationsfehler prüfen. | Deployment-/Startprotokoll |
| 12-COLLECTIONS-F01 | Fokus | aliasing, null, duplicates and ordering tests | Modulspezifischer Testreport |
| Risiko | Auswirkung | Gegenmaßnahme | Gate |
|---|---|---|---|
| mutation leaks and ordering semantics | NIEDRIG | aliasing, null, duplicates and ordering tests | vor Cutover |
Keine zusätzlichen Ressourcen.
LegacyInventory kann intern auf Inventory delegieren oder über einen Collection-Adapter kompatibel gehalten werden.