Fachlicher Vertrag: unverändert zu erhalten
- Typfehler werden zur Compile-Zeit statt per ClassCastException sichtbar.
- Repository-Identität und Optional-Semantik sind stabil.
- Keine unnötigen Wildcard-/Type-Token-Komplexitäten werden eingeführt.
Raw Types und Casts wird nachvollziehbar in typsichere generische Repositorys ü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 | SuppressWarnings | 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 | 2 erkannte Methoden | 5 erkannte Methoden | Methoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag. |
| Datenmodell | class RawBox | class InMemoryRepository, class TypedBox, interface Identifiable, interface Repository, record Customer | 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. |
runtime ClassCastException versus compile-time safety
generic boundaries, absent values and repository identity tests
Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.
| Legacy-Rolle / Datei | Modern-Rolle / Datei | Bedeutung |
|---|---|---|
| RawBox.java | TypedBox.java | Object-Container wird typsicher. |
| RawBox-Anwendungsfall | Repository.java + InMemoryRepository.java + Identifiable.java | Generischer Datenzugriffsvertrag wird ergänzt. |
| untypisierte Domänenwerte | Customer.java | Konkreter typsicherer Repository-Typ. |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| RawBox.java | class RawBox | SuppressWarnings | void set(Object value) Object get() | Generic Container (Legacy) – kapselt Werte, verliert durch Raw Types jedoch Typsicherheit. | 15 |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| Customer.java | record Customer | — | — | — | 4 |
| Identifiable.java | interface Identifiable | — | — | — | 5 |
| InMemoryRepository.java | class InMemoryRepository | — | T save(T entity) Optional<T> findById(ID id) List<T> findAll() | — | 19 |
| Repository.java | interface Repository | — | — | Generic Repository | 11 |
| TypedBox.java | class TypedBox | — | void set(T value) T get() | Generic Container | 14 |
| 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: Object-Container wird typsicher.
projects/13-generics/legacy/src/main/java/at/aydin/lab/generics/legacy/RawBox.java
package at.aydin.lab.generics.legacy;
// Design Pattern: Generic Container (Legacy) – kapselt Werte, verliert durch Raw Types jedoch Typsicherheit.
@SuppressWarnings({
"rawtypes", "unchecked"
}) public final class RawBox {
private Object value;
public void set(Object value) {
this.value = value;
}
public Object get() {
return value;
}
}
projects/13-generics/modern/src/main/java/at/aydin/lab/generics/modern/TypedBox.java
package at.aydin.lab.generics.modern;
// Design Pattern: Generic Container
// Zweck: Der gespeicherte Typ wird zur Compile-Zeit festgelegt; Laufzeit-Casts entfallen.
public final class TypedBox<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
--- RawBox.java
+++ TypedBox.java
@@ -1,15 +1,14 @@
-package at.aydin.lab.generics.legacy;
+package at.aydin.lab.generics.modern;
-// Design Pattern: Generic Container (Legacy) – kapselt Werte, verliert durch Raw Types jedoch Typsicherheit.
-@SuppressWarnings({
- "rawtypes", "unchecked"
-}) public final class RawBox {
- private Object value;
- public void set(Object value) {
+// Design Pattern: Generic Container
+// Zweck: Der gespeicherte Typ wird zur Compile-Zeit festgelegt; Laufzeit-Casts entfallen.
+public final class TypedBox<T> {
+ private T value;
+ public void set(T value) {
this.value = value;
}
- public Object get() {
+ public T get() {
return value;
}
}
Migrationsbedeutung: Generischer Datenzugriffsvertrag wird ergänzt.
projects/13-generics/legacy/src/main/java/at/aydin/lab/generics/legacy/RawBox.java
package at.aydin.lab.generics.legacy;
// Design Pattern: Generic Container (Legacy) – kapselt Werte, verliert durch Raw Types jedoch Typsicherheit.
@SuppressWarnings({
"rawtypes", "unchecked"
}) public final class RawBox {
private Object value;
public void set(Object value) {
this.value = value;
}
public Object get() {
return value;
}
}
projects/13-generics/modern/src/main/java/at/aydin/lab/generics/modern/Repository.java
package at.aydin.lab.generics.modern;
import java.util.*;
// Design Pattern: Generic Repository
// Zweck: Wiederverwendbarer, typsicherer Datenzugriffsvertrag für unterschiedliche Entitäten.
public interface Repository<ID, T extends Identifiable<ID>> {
T save(T entity);
Optional<T> findById(ID id);
List<T> findAll();
}
projects/13-generics/modern/src/main/java/at/aydin/lab/generics/modern/InMemoryRepository.java
package at.aydin.lab.generics.modern;
import java.util.*;
public final class InMemoryRepository<ID, T extends Identifiable<ID>> implements Repository<ID, T> {
private final Map<ID, T> data = new LinkedHashMap<>();
public T save(T entity) {
data.put(entity.id(), entity);
return entity;
}
public Optional<T> findById(ID id) {
return Optional.ofNullable(data.get(id));
}
public List<T> findAll() {
return List.copyOf(data.values());
}
}
Migrationsbedeutung: Konkreter typsicherer Repository-Typ.
projects/13-generics/legacy/src/main/java/at/aydin/lab/generics/legacy/RawBox.java
package at.aydin.lab.generics.legacy;
// Design Pattern: Generic Container (Legacy) – kapselt Werte, verliert durch Raw Types jedoch Typsicherheit.
@SuppressWarnings({
"rawtypes", "unchecked"
}) public final class RawBox {
private Object value;
public void set(Object value) {
this.value = value;
}
public Object get() {
return value;
}
}
projects/13-generics/modern/src/main/java/at/aydin/lab/generics/modern/Customer.java
package at.aydin.lab.generics.modern;
public record Customer(Long id, String name) implements Identifiable<Long> {
}
--- RawBox.java
+++ Customer.java
@@ -1,15 +1,4 @@
-package at.aydin.lab.generics.legacy;
+package at.aydin.lab.generics.modern;
-// Design Pattern: Generic Container (Legacy) – kapselt Werte, verliert durch Raw Types jedoch Typsicherheit.
-@SuppressWarnings({
- "rawtypes", "unchecked"
-}) public final class RawBox {
- private Object value;
- public void set(Object value) {
- this.value = value;
- }
-
- public Object get() {
- return value;
- }
+public record Customer(Long id, String name) implements Identifiable<Long> {
}
| ID | Ebene | Prüfung | erforderlicher Nachweis |
|---|---|---|---|
| 13-GENERICS-A01 | Integration/Contract | Build ist ohne unchecked-Warnungen. | Automatisierter Test und CI-Protokoll |
| 13-GENERICS-A02 | Integration/Contract | Falscher Typ ist nicht mehr kompilierbar. | Automatisierter Test und CI-Protokoll |
| 13-GENERICS-A03 | Integration/Contract | Find-by-ID liefert eindeutig Optional. | Automatisierter Test und CI-Protokoll |
| 13-GENERICS-A04 | Integration/Contract | Speichern überschreibt/ergänzt nach dokumentierter Regel. | Automatisierter Test und CI-Protokoll |
| 13-GENERICS-A05 | Integration/Contract | Generische API bleibt für Aufrufer verständlich. | Automatisierter Test und CI-Protokoll |
| 13-GENERICS-T01 | Unit | Fachlogik ohne Container oder externen Dienst testen. | Unit-Test |
| 13-GENERICS-T02 | Regression | Legacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen. | Vergleichsreport |
| 13-GENERICS-T03 | Negative | Fehlerhafte, leere und grenzwertige Eingaben prüfen. | Negativtest |
| 13-GENERICS-T04 | Operations | Start, Health, Shutdown und Konfigurationsfehler prüfen. | Deployment-/Startprotokoll |
| 13-GENERICS-F01 | Fokus | generic boundaries, absent values and repository identity tests | Modulspezifischer Testreport |
| Risiko | Auswirkung | Gegenmaßnahme | Gate |
|---|---|---|---|
| runtime ClassCastException versus compile-time safety | NIEDRIG | generic boundaries, absent values and repository identity tests | vor Cutover |
Keine zusätzlichen Ressourcen.
Ein begrenzter Adapter kann Object akzeptieren und intern validieren; er darf nicht zur dauerhaften neuen Raw-Type-Schicht werden.