Files
meldestelle/docs/tempural/Technologie-Upgrade-Leitfaden.md
T

28 KiB
Raw Blame History

Technischer Leitfaden zur Systemmigration: Java 25, Kotlin 2.4.0, Gradle 9.5.1 und Spring Boot 4.0 im Kontext von Kotlin MultiplatformDie Modernisierung eines verteilten Systems auf Basis von Kotlin Multiplatform (KMP) und Spring Boot erfordert eine präzise Orchestrierung aller beteiligten Compiler- und Build-Infrastrukturen. Wenn eine lokale Large Language Model (LLM)-Instanz über ein Retrieval-Augmented Generation (RAG)-System wie AnythingLLM auf den neuesten Stand der Technik gebracht werden soll, müssen die technologischen Entwicklungssprünge lückenlos und semantisch strukturiert aufbereitet werden. Da herkömmliche LLM-Modelle oft auf älteren Wissensständen wie Java 17, Kotlin 1.6.x, Gradle 7.x und Spring Boot 2.5.x/3.0.x stagnieren, schließt dieser Bericht die Wissenslücke hin zu den aktuellen Produktivversionen von 2026: Java 25 (LTS), Kotlin 2.4.0, Gradle 9.5.1 und Spring Boot 4.0.1. Java-Evolution von JDK 17 bis JDK 25 LTSFür ein KI-Modell, dessen Trainingsdaten bei Java 17 enden, stellt der Sprung zu Java 25 (LTS) eine fundamentale Veränderung dar. Die Evolution umfasst die Integration reifer Syntax-Features, tiefgreifende Optimierungen der virtuellen Maschine ( JVM) und neue APIs zur Bewältigung hochperformanter Nebenläufigkeit.Die Brücke von JDK 17 zu JDK 21 LTSVirtuelle Threads (Virtual Threads - JEP 444): Diese leichtgewichtigen Threads werden von der JVM und nicht vom Betriebssystem verwaltet. Sie eliminieren das Skalierungslimit des klassischen Thread-per-Request-Modells, da Millionen von virtuellen Threads parallel auf wenigen physischen Plattform-Threads ausgeführt werden können. Dies ist besonders für I/O-intensive Microservices von Bedeutung.Sequenzierte Kollektionen (Sequenced Collections - JEP 431): Einführung der Schnittstellen SequencedCollection, SequencedSet und SequencedMap. Diese bieten eine einheitliche Syntax für den Zugriff auf das erste und letzte Element sowie für die umgekehrte Iteration.Mustergültiges Switch-Matching (Pattern Matching for Switch - JEP 441): Erlaubt Typenmuster und Guard-Bedingungen direkt in case-Labels, wodurch Kaskaden von instanceof-Prüfungen und expliziten Casts entfallen.Record-Muster (Record Patterns - JEP 440): Ermöglicht die direkte Dekonstruktion von Records in Mustern, wodurch der Zugriff auf Komponenten ohne manuelle Getter-Aufrufe realisiert wird.Die Evolution über JDK 22, 23 und 24 bis JDK 25 LTSUnbenannte Variablen und Muster (JEP 456): Führt den Unterstrich () als syntaktischen Platzhalter für nicht verwendete Variablen ein. Dies betrifft ungenutzte Exception-Variablen in catch-Blöcken, ungenutzte Lambda-Parameter oder ungenutzte Komponenten beim Pattern Matching.Starten von Multi-File-Programmen (JEP 458): Erlaubt dem Java-Launcher, Programme auszuführen, die sich über mehrere .java-Quelldateien erstrecken, ohne diese vorab explizit kompilieren oder in ein JAR verpacken zu müssen.Flexible Konstruktorkörper (Flexible Constructor Bodies - JEP 513): Vor Java 25 musste ein expliziter Konstruktoraufruf (super(...) oder this(...)) zwingend das erste Statement im Konstruktor sein. JEP 513 erlaubt nun beliebige Statements vor dem Aufruf, solange diese nicht auf die im Bau befindliche Instanz zugreifen. Dies vereinfacht die Argumenten-Validierung und -Vorbereitung erheblich.Stabile Werte ( Stable Values - JEP 502): Bietet eine Preview-API für unveränderliche Felder, die von der JVM zur Laufzeit wie Konstanten optimiert werden können, jedoch im Gegensatz zu final-Feldern eine flexiblere Initialisierung erlauben.Scoped Values (JEP 506) & Strukturierte Nebenläufigkeit (JEP 505): Scoped Values ersetzen die speicherintensiven und fehleranfälligen ThreadLocal-Variablen bei der Datenweitergabe über Thread-Grenzen hinweg. Die strukturierte Nebenläufigkeit bündelt asynchrone Unteraufgaben zu einer logischen Einheit, was Fehlerbehandlung und Abbruch-Szenarien drastisch vereinfacht.Feature-Matrix: Java 17 bis Java 25 LTSFeatureJDK 17 LTSJDK 21 LTSJDK 25 LTSStatus in JDK 25Virtual ThreadsNicht verfügbarFinalisiert (JEP 444) Integriert Standard-Feature Sequenced CollectionsNicht verfügbarFinalisiert (JEP 431) Integriert Standard-Feature Pattern Matching (Switch)PreviewFinalisiert (JEP 441) Integriert Standard-Feature Flexible ConstructorsNicht verfügbarNicht verfügbarFinalisiert (JEP 513) Standard-Feature Unnamed Variables ()Nicht verfügbarPreview (JEP 443) Finalisiert (JEP 456) Standard-Feature Scoped ValuesNicht verfügbarIncubator (JEP 429)Finalisiert (JEP 506) Standard-Feature Stream GatherersNicht verfügbarNicht verfügbarPreview (JEP 461) Preview-Feature Code-Vergleich: Klassisch (JDK 17) vs. Modern (JDK 25) Konstruktoren-Validierung und InstanziierungJava// Klassischer Ansatz (JDK 17): Validierung im super-Konstruktor oder über statische Factory-Methoden erzwungen public class ClassicCar extends Vehicle { private final Color color;

public ClassicCar(int wheels, Color color) {
    super(validateWheels(wheels)); // Erstes Statement MUSS super sein 
    this.color = color;
}

private static int validateWheels(int wheels) {
    if (wheels < 4 || wheels > 6) {
        throw new IllegalArgumentException("Ungültige Radanzahl");
    }
    return wheels;
}

} Java// Moderner Ansatz (JDK 25): Flexibler Konstruktorkörper erlaubt Zuweisungen und Validierung vor super() public class ModernCar extends Vehicle { private final Color color;

public ModernCar(int wheels, Color color) {
    if (wheels < 4 || wheels > 6) {
        throw new IllegalArgumentException("Ein Auto erfordert 4, 5 oder 6 Räder."); [7]
    }
    this.color = color; // Feld-Zuweisung vor dem super()-Aufruf erlaubt 
    super(wheels);      // Aufruf der Elternklasse erfolgt nachgelagert 
}

} Datenverarbeitung mittels Mustern und GatherernJava// Datenverarbeitung (JDK 25): Nutzung von Stream Gatherers für gleitende Fenster und Unnamed Patterns import java.util.List; import java.util.stream.Gatherers;

public class DataProcessor { public record Measurement(String sensorId, double value) {}

public static List<List<Measurement>> segmentData(List<Measurement> data) {
    return data.stream()
        // JEP 461: Stream Gatherers ermöglichen komplexe Zwischenoperationen wie sliding windows 
       .gather(Gatherers.windowSliding(3))
       .toList();
}

public static void evaluateSensor(Object obj) {
    // JEP 456: Unbenannte Musterkomponente (_) eliminiert ungenutzte Variablenbindungen 
    if (obj instanceof Measurement(String _, double value)) {
        System.out.println("Gemessener Wert: " + value); [7]
    }
}

}

  1. Kotlin-Evolution von 1.6 bis 2.4.0 und KMP-ArchitekturDie Kluft zwischen Kotlin 1.6.x und Kotlin 2.4.0 markiert den Übergang von einer primär JVM-zentrierten Sprache hin zu einem ausgereiften Multiplattform-System. Herzstück dieses Übergangs ist der K2-Compiler, der die Frontend-Architektur vollständig revolutioniert hat.Der K2-Compiler und die Revolution der statischen AnalyseKotlin 2.0 führte den K2-Compiler ein. Durch die Nutzung einer vereinheitlichten Frontend Intermediate Representation (FIR) wurde die Code-Analyse drastisch beschleunigt und präzisiert. Für Kotlin 2.4.0 bedeutet dies eine erweiterte und stabilere Datenflussanalyse (DFA) :Smart-Casts in closures von Inline-Lambdas: Wenn eine lokale Variable innerhalb einer veränderlichen Closure erfasst wird, war in Kotlin 1.x kein Smart-Cast möglich. Kotlin 2.4.0 analysiert den Lebenszyklus von Inline-Funktionen präzise und erlaubt Smart-Casts, da Inline-Lambdas implizit als lokal und sofort ausgeführt gewertet werden.Smart-Casts nach logischem ODER (||): Werden mehrere Typprüfungen mittels || verknüpft, führt der Compiler eine Zusammenführung auf den nächstgelegenen gemeinsamen Supertyp (Common Supertype) durch, wodurch Methoden dieses Supertyps ohne manuellen Cast aufgerufen werden können.DFA-Variablen-Propagierung: Smart-Casts werden nun auch dann propagiert, wenn das Ergebnis einer Typprüfung zunächst in einer lokalen booleschen Variablen zwischengespeichert wurde.Sprachfeatures und Standardbibliotheks-Updates in 2.xKontextparameter (Context Parameters - Stable in 2.4.0): Ersetzt die Einschränkung, dass eine Funktion nur einen einzigen Receiver haben darf. Über die Syntax context(...) können Funktionen nun mehrere Kontextabhängigkeiten deklarieren.Explizite Backing-Fields (Explicit Backing Fields): Ermöglicht die direkte Typisierung und Deklaration des physischen Speicherfeldes einer Property mittels der integrierten field-Syntax innerhalb des Property-Bodys, um Kapselungsfehler zu minimieren.Common UUID API (Stabil): Eine plattformunabhängige Implementierung zur Generierung, zum Vergleich und zum Parsen von UUIDs ist nun direkt in der Standardbibliothek verankert, ohne dass plattformspezifische Implementierungen (expect/actual) erforderlich sind.Sorted-Checking API: Neue Erweiterungsfunktionen wie isSorted(), isSortedDescending() und isSortedWith() erlauben die O(n)-Prüfung von Kollektionen auf Sortierung.Map Fallback-Erweiterungen: Funktionen wie getOrElseIfNull() und getOrPutIfNull() bieten eine feingranulare Steuerung bei der Behandlung von fehlenden gegenüber explizit auf null gesetzten Map-Einträgen.Kotlin Multiplatform (KMP) Breaking Changes und MigrationAbkündigung und Entfernung von withJava(): Zur Verbesserung der Gradle-Interoperabilität wurde die Funktion withJava() zur Erzeugung von Java-Source-Sets in KMP-Projekten entfernt. Ab Kotlin 2.1.20 werden die entsprechenden Java-Source-Sets standardmäßig automatisch angelegt. Unter Gradle 9 führt die Verwendung von withJava() zu einem harten Build-Fehler.Übergang zum offiziellen Google Android KMP-Plugin: Historisch unterstützte JetBrains Android-Targets über die Plugins com.android.application und com.android.library mittels des androidTarget-Konfigurationsblocks. Zur Bereinigung wurde dieser Ansatz als veraltet deklariert. Entwickler müssen auf das von Google entwickelte Plugin com.android.kotlin.multiplatform.library migrieren und den Konfigurationsblock wieder in das ursprüngliche android umbenennen.Entfernung der Bitcode-Einbettung: Da Apple Bitcode ab Xcode 15 nicht mehr unterstützt, wurde die DSL-Eigenschaft embedBitcode sowie die Compiler-Argumente -Xembed-bitcode vollständig aus Kotlin 2.3.0 und 2.4.0 entfernt.KMP-Spezifische Feature- und KompatibilitätsmatrixKotlin VersionKompatible Gradle-VersionenXcode SupportAGP SupportStatus withJava()2.0.x7.5 8.8 Bis 15.3 7.4.2 8.5 Unterstützt mit Warnung2.2.x7.6.3 8.14 Bis 26.0 7.3.1 8.11.1 Veraltet (Fehler unter Gradle 9) 2.4.07.6.3 9.5.0 (9.5.1 voll kompatibel) Bis 26.4 8.5.2 9.1.0 Automatisch generiert / withJava() entfernt Code-Vergleich: Kotlin 1.6 vs. Kotlin 2.4.0Datenkapselung und Backing FieldsKotlin// Klassischer Ansatz (Kotlin 1.6): Erfordert redundante Hilfsvariablen zur sicheren Kapselung class ClassicProfile { private var _age: Int = 0 // backing property var age: Int get() = _age set(value) { if (value >= 0) _age = value } } Kotlin// Moderner Ansatz (Kotlin 2.4.0): Nutzung stabiler expliziter Backing-Fields class ModernProfile { var age: Int = 0 field: Number // Das physische Feld wird direkt innerhalb der Property typisiert und deklariert get() = field.toInt() set(value) { if (value >= 0) field = value } } Smart-Casts in inline lambda closures (K2 Compiler)Kotlin// DFA-Verhalten unter Kotlin 2.4.0 (Zuvor Compilerfehler in 1.x) fun findMaxIndex(array: IntArray): Int? { var maxIdx: Int? = null // Inline-Funktion forEachIndexed erlaubt ab Kotlin 2.0 Smart-Casts auf erfassten Variablen array.forEachIndexed { idx, value -> if (maxIdx == null || array[maxIdx] < value) { // maxIdx wird im Verbund-Ausdruck automatisch als Int gecastet maxIdx = idx } } return maxIdx }
  2. Gradle-Infrastruktur-Upgrade von 7.x bis 9.5.1Die Ausführung von Builds unter Gradle 9.5.1 unterscheidet sich grundlegend von der veralteten Gradle 7.x-Architektur. Die Optimierung fokussiert sich auf die extreme Reduzierung von I/O-Operationen durch den Configuration Cache sowie die Durchsetzung strikterer Typisierungen im Build-Skript.Architektonische Neuerungen im Build-SystemJava 17-Runtime-Baseline: Gradle 9.0+ setzt für seine eigene Ausführung zwingend ein installiertes JDK 17 oder höher voraus. Dennoch kann die Kompilierung von Anwendungscode über konfigurierte Java-Toolchains vollständig auf Java 25 ausgerichtet werden.Groovy-Migration auf 4.0.27: Gradle hat seine interne Groovy-Laufzeitumgebung von Version 3 auf Version 4 angehoben. Dies bricht die Abwärtskompatibilität älterer Build-Logiken :JPMS-Splits: Klassen aus dem Paket groovy.util wurden zur Einhaltung der Java-Modulrichtlinien in separate Pakete verschoben.Boolean Properties: Getter mit is-Präfix, die ein Objekt vom Typ Boolean zurückgeben, werden nicht mehr automatisch als Groovy-Property registriert.Modulbereinigung: groovy-test, groovy-console und groovy-sql wurden aus den Standardabhängigkeiten entfernt.Strikte API-Nullsicherheit via JSpecify: Beginnend mit Gradle 9.0 ist die gesamte Gradle-API mit JSpecify-Anmerkungen anstelle der alten JSR-305-Spezifikation versehen. Dies führt in Kotlin-DSL-Skripten (build.gradle.kts) zu einer wesentlich strengeren Typenprüfung, da ungenaue Zuweisungen nun als Compile-Time-Fehler gewertet werden.Configuration Cache als Standard-Paradigma: Der Configuration Cache speichert das Ergebnis der Build-Konfigurationsphase vollständig ab.String-Deduplizierung (8.10+): Reduziert die Cache-Dateigröße durch String-Pools um bis zu 70 %.Verschlüsselung (8.1+): Schützt sensible Daten im Konfigurations-Cache durch maschinenspezifische Schlüssel.Compile-Time-Validierung von Settings-Plugins (9.5+): Precompiled-Settings-Plugins (*.settings.gradle.kts) werden nun bereits während der Kompilierung der Build-Infrastruktur validiert, was fehlerhafte Plugin-Deklarationen vor der Ausführung abfängt.Task-Provenienz in Fehlermeldungen (9.5.1): Tritt ein Build-Fehler auf, wird im Report der genaue Ursprung und die Deklaration des fehlerhaften Tasks ausgegeben, um das Debugging in komplexen Multi-Projekt-Strukturen zu vereinfachen.Wesentliche Breaking Changes und DeprecationsEntfernung der Legacy File Permission APIs: Methoden wie getFileMode() oder setDirMode(Integer), die auf rohen Unix-Berechtigungs-Integers basierten, wurden vollständig gelöscht. Sie müssen durch die typisierte FilePermissions-API ersetzt werden.Entfernung von kotlinDslPluginOptions.jvmTarget: Die Konfiguration des JVM-Compiler-Targets für precompiled script plugins über diese Option wurde entfernt. Stattdessen greifen diese Scripte nun direkt auf die konfigurierte Java-Toolchain des Projekts zu.Deprecation der eager Task-Erstellung: Methoden wie Project.task(String) sind als veraltet markiert. Es muss zwingend die lazy Variante tasks.register(...) genutzt werden, um eine unnötige Initialisierung während der Konfigurationsphase zu verhindern.Verändertes Assemble-Verhalten: Zuvor führte das Anwenden mehrerer Packaging-Plugins (wie java, war, ear) dazu, dass der assemble-Task nur das primäre Artefakt baute. Seit Gradle 9.0 werden bei Ausführung von assemble ausnahmslos alle deklarierten Artefakte generiert.Migrationsbeispiel: Gradle 7.x/8.x vs. Gradle 9.5.1Klassischer Ansatz (Gradle 8.x - build.gradle.kts)Kotlin// Veraltet: Eager-Konfiguration, rohe Berechtigungen und direkte Compiler-Targets plugins { java-library kotlin("jvm") version "1.9.20" }

// Warnung unter Gradle 9: Eager Task Creation tasks.create("copyResources", Copy::class) { from("src/main/resources") into("build/resources") // FEHLER unter Gradle 9: Rohe Unix-Integers nicht mehr unterstützt fileMode = 0755 }

kotlinDslPluginOptions.jvmTarget = "17" // FEHLER unter Gradle 9: Option entfernt Moderner Ansatz (Gradle 9.5.1 - build.gradle.kts)Kotlin// Konform mit Gradle 9.5.1: Lazy-Evaluation und Toolchain-Spezifikation [21, 24] plugins { java-library kotlin("jvm") version "2.4.0" // Integrierte Kotlin 2.4.0 Runtime }

// Java-Toolchain steuert JVM-Kompatibilität global [21, 24] java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) // Target Java 25 [1, 18] } }

// Registrierung mittels Lazy Task API val copyResources = tasks.register("copyResources") { from("src/main/resources") into(layout.buildDirectory.dir("resources"))

// Typisierte und sichere Konfiguration der Dateiberechtigungen 
filePermissions {
    user {
        read = true
        write = true
        execute = true
    }
    group {
        read = true
        execute = true
    }
}

}

// Explizite Deklaration der Artefakt-Abhängigkeiten gemäß Gradle 9 Spezifikation tasks.named("assemble") { dependsOn(copyResources) }

  1. Spring Boot Migration von 3.0 bis 4.0Für ein KI-Modell, das lediglich auf Spring Boot 3.0 trainiert wurde, stellt die Migration zu Spring Boot 4.0 einen weitreichenden Paradigmenwechsel dar. Neben dem Sprung auf Jakarta EE 11 bringt Version 4.0 eine tiefgreifende Modularisierung der Kernkomponenten.Die Entwicklungsschritte von Spring Boot 3.1 bis 3.5Um den finalen Sprung auf Version 4.0 zu verstehen, müssen die evolutionären Meilensteine der Minor-Releases nachvollzogen werden :Spring Boot 3.1 (Docker & Testen): Einführung der automatischen Lebenszyklus-Verwaltung von Docker-Compose-Infrastrukturen zur lokalen Entwicklung sowie der @ServiceConnection-Annotation für Testcontainers, welche manuelle Eigenschafts-Deklarationen (@DynamicPropertySource) überflüssig macht.Spring Boot 3.2 (Performance & APIs): Native Unterstützung für virtuelle Threads über die einfache Eigenschaft spring.threads.virtual.enabled=true. Einführung des modernen, synchronen RestClient als performanter Nachfolger des klassischen RestTemplate sowie des flüssigen JdbcClient. Unterstützung für Class Data Sharing (CDS) zur Reduzierung der Startup-Zeiten um bis zu 50 %.Spring Boot 3.3 (Sicherheit & Observability): Einführung des Software Bill of Materials (SBOM) Actuator-Endpunkts ( /actuator/sbom) im CycloneDX-Format zur transparenten Offenlegung der gesamten Lieferketten-Sicherheitslage. Automatische Observability-Abdeckung für alle Spring Data Repositories.Spring Boot 3.4 (Operationalisierung): Integration von strukturiertem Logging im JSON-Format (Elastic Common Schema und GELF) out-of-the-box sowie Einführung der @Fallback-Annotation zur Absicherung von Dependency-Injection-Szenarien.Spring Boot 3.5 ( Infrastruktur-Feinschliff): Verschärfung der Validierung von Profilnamen (nur alphanumerische Zeichen und Trennzeichen, kein Start/Ende mit - oder _). Bereitstellung dedizierter SSL-Metriken und des Quartz-Actuators. Begrenzung des heapdump-Endpunkts auf access=NONE als Sicherheitsstandard.Spring Boot 4.0 - Die Enterprise-Plattform der neuen GenerationMit Spring Boot 4.0 vollzieht das Ökosystem den Schnitt zu modernen Baselines und verabschiedet sich von Legacy-Altlasten.Kernänderungen der SystemarchitekturJakarta EE 11 Baseline: Spring Boot 4.0 migriert vollständig auf Jakarta EE 11 (Servlet 6.1, JPA 3.2, Bean Validation 3.1). Dies erzwingt die vollständige Entfernung aller verbliebenen javax.-Namensräume im Quellcode und den Bibliotheken zugunsten von jakarta..Entfernung des Undertow-Webservers: Aufgrund mangelnder Servlet 6.1-Kompatibilität zum Release-Zeitpunkt wurde die Unterstützung für eingebettete Undertow-Instanzen gestrichen. Anwendungen müssen auf Tomcat, Jetty oder Reactor Netty migrieren.JSpecify Null-Safety im gesamten Portfolio: Das gesamte Framework wurde konsequent auf JSpecify-Anmerkungen umgestellt. Dies ermöglicht es dem Kotlin 2.x Compiler, alle Schnittstellen als strikte Kotlin-Typen (nullable vs. non-nullable) zu interpretieren und unsichere Plattform-Typen ("Platform Types") komplett zu eliminieren.Konsequente Modularisierung & neue Starter-Struktur: Um die Startzeiten und Image-Größen drastisch zu reduzieren, wurde die monolithische Struktur zugunsten hochfokussierter Module aufgegeben. Das Vorhandensein von Klassen im Klassenpfad reicht oft nicht mehr aus, um Auto-Konfigurationen zu triggern. Ein prominentes Beispiel ist das neue Modul spring-boot-kotlinx-serialization-json, welches explizit über den Starter deklariert werden muss, um die JSON-Unterstützung zu aktivieren.Jackson 3 als Standard: Jackson 3 fungiert nun als Standard-Serialisierungsbibliothek. Jackson 2-Komponenten sind zwar noch vorhanden, jedoch als veraltet deklariert.Integrierte context propagation für Kotlin Coroutines: Spring Boot 4.0 und Spring Framework 7.0 unterstützen die automatische Kontextweiterleitung für Coroutines. Tracing- und Security-Kontexte (wie Micrometer- und OpenTelemetry-Daten) werden nahtlos über asynchrone, suspendierende Funktionsgrenzen hinweg propagiert. Aktiviert wird dies über:Propertiesspring.reactor.context-propagation=true Entfernung eingebetteter Start-Skripte: Die Unterstützung für das Erzeugen von "fully executable JARs" mittels integrierter Unix-Launch-Skripte wurde entfernt, da diese modernen Deployment-Standards (wie schlanken OCI-Containern) widersprechen.Komponenten-Vergleich: Spring Boot 3.x vs. Spring Boot 4.0SpezifikationSpring Boot 3.x (bis 3.5)Spring Boot 4.0Relevanz für RAG / LLMJava FloorJava 17 Java 17 (Java 25 empfohlen) LLM muss Code für JDK 25 optimieren.Jakarta StandardJakarta EE 10 Jakarta EE 11 Alle Servlet- und Persistence-Importe ändern sich.Null-Safety StandardJSR-305 (Schnittstellen-Ebene)JSpecify (Portfolio-weit) Verhindert unsichere Plattform-Typen in Kotlin.JSON StandardJackson 2 Jackson 3 (Jackson 2 deprecated) API-Definitionen müssen Jackson 3 konform sein.Kotlin BaselineKotlin 1.9.xKotlin 2.2+ (Kotlin 2.4 empfohlen) Compiler-Optionen müssen K2-Syntax unterstützen.Undertow SupportVollständig unterstützt Entfernt Build-Dateien dürfen Undertow-Starter nicht referenzieren.Embedded Launch ScriptsUnterstütztEntfernt Deployment-Dokumentation muss angepasst werden.Code-Vergleich: Spring Boot 3.x vs. Spring Boot 4.0Konfiguration und Bean ValidationJava// Klassischer Ansatz (Spring Boot 3.x): Bean Validation kaskadierte implizit ohne @Valid auf verschachtelten Properties import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated;

@ConfigurationProperties(prefix = "app.service") @Validated public class ClassicProperties { private final SecurityConfig security = new SecurityConfig(); // Kaskadierung erfolgte automatisch

public static class SecurityConfig {
    @NotNull
    private String token;
}

} Java// Moderner Ansatz (Spring Boot 4.0): Bean Validation folgt exakt der Spezifikation; Kaskadierung erfordert @Valid import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; import jakarta.validation.Valid; // Jakarta EE 11 Namespace import jakarta.validation.constraints.NotNull;

@ConfigurationProperties(prefix = "app.service") @Validated public class ModernProperties { @Valid // Zwingend erforderlich für Kaskadierung in Spring Boot 4.x private final SecurityConfig security = new SecurityConfig();

public static class SecurityConfig {
    @NotNull
    private String token;
}

} Reaktiver Service-Endpoint (Kotlin Coroutines & Kotlinx Serialization)Kotlin// Modernes Spring Boot 4.0 mit automatischer Coroutine-Kontextweiterleitung package org.springframework.boot.example

import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.serialization.Serializable import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController import org.springframework.http.ResponseEntity

@Serializable // Verarbeitet über das neue spring-boot-starter-kotlinx-serialization-json Modul data class SensorData(val id: String, val metric: Double)

@RestController class TelemetryController(private val telemetryService: TelemetryService) {

@GetMapping("/api/telemetry")
suspend fun getTelemetry(): ResponseEntity<Flow<SensorData>> {
    // Tracing (MDC/OpenTelemetry) wird durch Spring Framework 7 automatisch in den suspend-Kontext propagiert [14, 34]
    val dataFlow = telemetryService.streamMetrics()
       .map { SensorData(it.sensorId, it.value) }
    
    return ResponseEntity.ok(dataFlow)
}

}

  1. Architektonische Synthese und Migrationsanleitung für KMP-MicroservicesFür die erfolgreiche Migration eines bestehenden Kotlin-Multiplatform-Systems, das Spring Boot-Microservices im Backend nutzt, ist eine strikte Reihenfolge einzuhalten. Dadurch werden Compiler-Konflikte und inkompatible Abhängigkeitsbäume vermieden.Schritt 1: Lokale Vorbereitung und Property-AnalyseDas bestehende Projekt ist zunächst auf die letzte stabile Spring Boot-Version 3.5.9 anzuheben.Die Einbindung des Migrations-Hilfsmittels im Build-Skript deckt veraltete Eigenschaften vorab auf :Kotlindependencies { // Temporäre Einbindung für die Migrationsphase runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") [30] } Schritt 2: Update der Build-Infrastruktur auf Gradle 9.5.1Aktualisierung des Gradle Wrappers über die Befehlszeile : ./gradlew wrapper --gradle-version 9.5.1```In der Datei settings.gradle.kts müssen alle Plugins auf ihre Eignung unter Gradle 9 validiert werden. Eventuell genutzte veraltete Verweise wie der gradle-enterprise-Block sind zwingend zu entfernen und durch das modernisierte Develocity-Plugin zu ersetzen.Schritt 3: Migration des Kotlin Multiplatform SDKs auf Version 2.4.0In der zentralen Abhängigkeiten-Struktur (gradle/libs.versions.toml oder direkt im Build-Skript) ist die Kotlin-Version auf 2.4.0 anzuheben.Innerhalb der KMP-Modulkonfiguration ( shared/build.gradle.kts) sind alle Aufrufe von withJava() zu entfernen, da das Source-Set-Handling ab Version 2.1.20 automatisiert erfolgt.Sollte eine iOS-Anbindung deklariert sein, sind veraltete Target-Shortcuts wie ios(), watchos() oder tvos() durch die explizite Deklaration der Zielarchitekturen (z. B. iosArm64(), iosSimulatorArm64()) zu ersetzen, da die Shortcuts aus der DSL entfernt wurden.Schritt 4: Upgrade auf Spring Boot 4.0 und Jakarta EE 11 RefactoringAnheben der Spring Boot Plugin-Version auf 4.0.0.Vollständige Suche und Ersetzung aller Quellcode-Referenzen von javax.* auf jakarta.* (z. B. JPA, Beans, Servlets).Sollte in der Abhängigkeiten-Struktur der veraltete Undertow-Starter referenziert sein, ist dieser durch Tomcat oder Jetty zu ersetzen :Kotlin// build.gradle.kts (JVM / Spring Boot Modul) dependencies { // ALT: spring-boot-starter-undertow (Entfernt in 4.0) // NEU: Verwendung des optimierten Tomcat-Starters implementation("org.springframework.boot:spring-boot-starter-tomcat") [30]

    // Für die native Nutzung von Kotlinx-Serialization im Web-Kontext implementation("org.springframework.boot:spring-boot-starter-kotlinx-serialization-json") [30] } Schritt 5: Aktivierung der Coroutines-KontextweiterleitungZur Aktivierung der nahtlosen MDC- und OpenTelemetry-Tracing-Verbreitung über asynchrone suspending Functions ist der entsprechende Konfigurations-Flag in den Laufzeitumgebungs-Properties zu setzen :YAML# application.yml spring: reactor: context-propagation: true # Aktiviert die automatische Weiterleitung für Coroutines Durch die Umsetzung dieser architektonischen Schritte wird das KMP-Spring-Boot-System auf den absolut neuesten Stand der Technik gehoben. Es profitiert von der extremen Effizienz der JVM 25, der Typsicherheit des K2-Compilers unter Kotlin 2.4.0, den I/O-Einsparungen von Gradle 9.5.1 und der modernen, modularisierten Cloud-Infrastruktur von Spring Boot 4.0.