Zum Inhalt springen
SAP Commerce Cloud Java 21 + Spring 6 Migration: Ein Leitfaden für Entwickler
Implementation · ·11 Min. Lesezeit

SAP Commerce Cloud Java 21 + Spring 6 Migration: Ein Leitfaden für Entwickler

Spadoom

Spadoom

SAP CX Partner & Consultancy

Teilen

Wenn Sie Custom Java Code auf SAP Commerce Cloud betreiben, haben Sie eine harte Deadline: 30. Juni 2026. Ab diesem Datum setzen SAP-Commerce-Cloud-Umgebungen Java 21 voraus. Keine Verlängerungen. Keine Kulanzfrist. Deployments, die auf Java 17 gebaut sind, passieren die Build-Pipeline nicht mehr.

Und Java 21 kommt nicht allein. Die Plattform ist von Spring Framework 5 auf Spring Framework 6 gewechselt, was die Jakarta-EE-Namespace-Migration mit sich bringt. Das heisst: javax.servlet, javax.persistence, javax.validation — die Imports, die Sie seit 15 Jahren schreiben — sind weg. Ersetzt durch jakarta.*.

Das ist keine kosmetische Änderung. Sie betrifft Ihre Servlets, Ihre JPA-Entitäten, Ihre Validierungsannotationen, Ihre Spring-Security-Konfiguration und potenziell jede Custom Extension, die Sie gebaut haben. Die gute Nachricht: Es gibt Tooling, das rund 80 % der mechanischen Arbeit erledigt. Die restlichen 20 % — das ist echte Engineering-Arbeit.

TL;DR: SAP Commerce Cloud verlangt Java 21 bis zum 30. Juni 2026. Die Plattform ist bereits auf Spring 6 und Jakarta EE 10 umgezogen, was den javax.*-Namespace obsolet macht. OpenRewrite automatisiert den Grossteil der Namespace-Migration, aber Spring-Security-Umbauten, benutzerdefinierte AOP-Konfigurationen und Reflection-lastiger Code erfordern manuelle Arbeit. Rechnen Sie mit 2–4 Wochen für die Migration und 2–3 Wochen für Regressionstests. Fangen Sie jetzt an — Teams, die bis Mai warten, entdecken Probleme, die sich nicht mehr in vier Wochen lösen lassen.

Was sich ändert und warum

Drei Verschiebungen passieren gleichzeitig. Sie hängen zusammen, brechen aber unterschiedliche Teile Ihres Codes.

Java 17 auf Java 21. SAP Commerce Cloud hat Java 17 als Minimum mit dem Release 2211 eingeführt. Jetzt geht die Plattform auf Java 21, das seit September 2023 ein Long-Term-Support-Release ist. Java 21 bringt Virtual Threads, Pattern Matching für switch, Record Patterns und Sequenced Collections. Die meisten davon sind additiv — sie brechen bestehenden Code nicht. Was bricht: Entfernte APIs, die seit Java 9 deprecated waren, aber in 17 noch funktionierten, und die strengere Kapselung von JDK-Interna, auf die manche Bibliotheken via Reflection zugreifen.

Spring 5 auf Spring 6. Spring Framework 6.0 erfordert Java 17+ und nutzt die Jakarta-EE-9+-APIs als Basis. Das ist die grosse Änderung. Spring 6 hat die Unterstützung für den javax.*-Namespace komplett eingestellt. Jedes Spring-Modul — Web MVC, Security, Data JPA, AOP — basiert jetzt auf den jakarta.*-Pendants. Wenn Ihr Custom Code Spring-Klassen erweitert oder Spring-Interfaces implementiert, die javax.*-Typen referenzieren, kompiliert er gegen Spring 6 nicht mehr.

Jakarta EE 9/10 Namespace-Migration. Die Java-Community hat die javax.*-Pakete in jakarta.* umbenannt, nachdem Oracle Java EE an die Eclipse Foundation übertragen hatte. Das ist eine mechanische Änderung (Paketumbenennung), aber sie ist allgegenwärtig. Jedes Import-Statement, jeder vollqualifizierte Klassenname in XML-Konfigurationen, jede String-Referenz auf javax.persistence.Entity — alles muss aktualisiert werden.

Einen tieferen Einblick, wie die Architektur von Commerce Cloud solche Plattformänderungen handhabt, finden Sie in unserem Leitfaden zur SAP Commerce Cloud Architektur.

Die Timeline

SAP hat diesen Wechsel phasenweise ausgerollt. Was bereits passiert ist und was kommt:

DatumEreignis
2023 Q3Java 21 LTS veröffentlicht von Oracle
2024 Q2SAP Commerce Cloud 2211.x Patch fügt Java-21-Kompatibilität hinzu
2025 Q1Spring 6 / Jakarta EE im Plattform-Code übernommen
2025 Q3SAP kündigt Java 21 als obligatorische Laufzeitumgebung an, Java 17 Builds werden deprecated
2026 Q1Migrations-Tooling und Dokumentation auf SAP Help Portal veröffentlicht
2026-06-30Deadline: Java-17-Builds blockiert. Java 21 erforderlich.

Das Fenster zwischen «Tooling verfügbar» und «Deadline» beträgt ungefähr sechs Monate. Das klingt komfortabel. Ist es nicht. Die meisten Commerce-Cloud-Projekte tragen 50’000–200’000 Zeilen Custom Java Code über Dutzende von Erweiterungen. Die Namespace-Migration allein erzeugt Tausende von Dateiänderungen. Das Testen dauert länger als die Migration selbst.

Unsere Empfehlung: Starten Sie die Migration jetzt. Lassen Sie das automatisierte Tooling laufen, beheben Sie, was es nicht kann, und beginnen Sie mit Regressionstests. Teams, die in Q2 2026 starten, haben Zeit für zwei vollständige Testzyklen. Teams, die im Juni anfangen, haben Zeit für Panik.

Breaking Changes Checkliste

Hier ist, was Sie erwartet, grob geordnet nach Häufigkeit und Auswirkung.

javax.* zu jakarta.* Namespace-Migration

Das ist die umfassendste Änderung. Jede Referenz auf diese Pakete muss aktualisiert werden:

Alt (javax.*)Neu (jakarta.*)Betroffener Code
javax.servlet.*jakarta.servlet.*Filter, Custom Controller, Request/Response Wrapper
javax.persistence.*jakarta.persistence.*JPA-Entitäten, Typ-Konverter, @Entity, @Column
javax.validation.*jakarta.validation.*Bean Validation, @NotNull, @Size, Custom Validators
javax.annotation.*jakarta.annotation.*@PostConstruct, @PreDestroy, @Resource
javax.inject.*jakarta.inject.*@Inject, @Named
javax.ws.rs.*jakarta.ws.rs.*JAX-RS-Endpunkte (falls vorhanden)

Vorher:

import javax.servlet.http.HttpServletRequest;
import javax.persistence.Entity;
import javax.persistence.Column;
import javax.validation.constraints.NotNull;

@Entity
public class CustomProduct {
    @Column(nullable = false)
    @NotNull
    private String customField;
}

Nachher:

import jakarta.servlet.http.HttpServletRequest;
import jakarta.persistence.Entity;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;

@Entity
public class CustomProduct {
    @Column(nullable = false)
    @NotNull
    private String customField;
}

Einfaches Suchen-und-Ersetzen? Grösstenteils. Aber achten Sie auf String-Literale und XML-Dateien, in denen javax.persistence als vollqualifizierter Name vorkommt. OpenRewrite fängt das meiste ab. Manuelles Grep den Rest.

Spring Security Änderungen

Spring Security 6 hat mehrere Breaking Changes eingeführt, die Commerce-Cloud-Projekte betreffen. Die grösste: WebSecurityConfigurerAdapter ist weg.

Vorher (Spring Security 5):

@Configuration
@EnableWebSecurity
public class CustomSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .antMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated();
    }
}

Nachher (Spring Security 6):

@Configuration
@EnableWebSecurity
public class CustomSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            );
        return http.build();
    }
}

Wichtige Änderungen:

  • WebSecurityConfigurerAdapter entfernt — verwenden Sie stattdessen SecurityFilterChain-Beans
  • authorizeRequests() ersetzt durch authorizeHttpRequests()
  • antMatchers() ersetzt durch requestMatchers()
  • csrf(), cors(), sessionManagement() verwenden jetzt ausschliesslich die Lambda-DSL
  • SecurityContext nutzt standardmässig RequestAttributeSecurityContextRepository (nicht session-basiert)

Wenn Ihr Commerce-Cloud-Projekt benutzerdefinierte Spring-Security-Konfigurationen für Storefront-Authentifizierung, B2B-Login oder Backoffice-Zugriff hat — diese müssen manuell umgeschrieben werden. Die Lambda-DSL ist besser komponierbar, aber man kann nicht einfach Methoden umbenennen.

Spring MVC Deprecations

Spring 6 hat mehrere Patterns entfernt, die in 5.x deprecated waren:

  • @RequestMapping Rückgabetyp-Änderungen: Methoden, die String als View-Namen zurückgeben, funktionieren weiterhin, aber die ModelAndView-Behandlung hat subtile Verhaltensänderungen bei Redirect-Semantik.
  • CommonsMultipartResolver ersetzt durch StandardServletMultipartResolver. Wenn Sie benutzerdefiniertes Datei-Upload-Handling konfiguriert haben, aktualisieren Sie die Resolver-Bean.
  • Trailing-Slash-Matching standardmässig deaktiviert. /api/products/ und /api/products sind jetzt unterschiedliche Routen. Wenn Ihre Storefront oder API-Clients auf Trailing-Slash-Toleranz angewiesen sind, konfigurieren Sie PathMatchConfigurer.setUseTrailingSlashMatch(true) — planen Sie aber, die URLs langfristig zu korrigieren.

Hibernate 6 Änderungen (JPA)

SAP Commerce Cloud nutzt Hibernate als JPA-Provider. Der Wechsel zu Jakarta EE bedeutet Hibernate 6.x, was eigene Änderungen mit sich bringt:

  • Sequenzbasierte ID-Generierung als Standard. Hibernate 6 bevorzugt SEQUENCE gegenüber IDENTITY für @GeneratedValue. Wenn Sie auf Auto-Increment-Verhalten angewiesen sind, setzen Sie explizit strategy = GenerationType.IDENTITY.
  • Überarbeitung des Typsystems. Benutzerdefinierte UserType-Implementierungen müssen aktualisiert werden. Das UserType-Interface hat seine generische Signatur geändert.
  • @Type-Annotations-Änderungen. @Type(type = "yes_no") wird zu @Convert(converter = YesNoConverter.class) oder @JdbcTypeCode(Types.CHAR).
  • Implizite @Column(length)-Durchsetzung. Hibernate 6 erzwingt die Column-Length-Validierung strikter auf Schemaebene. Spalten, die mit impliziten Standardwerten funktionierten, können jetzt Validierungs-Exceptions werfen.

Vorher:

@Type(type = "yes_no")
private Boolean active;

Nachher:

@Convert(converter = org.hibernate.type.YesNoConverter.class)
private Boolean active;

Entfernte Java-APIs

Java 21 hat mehrere APIs entfernt, die seit Java 9–11 als deprecated-for-removal markiert waren. Prüfen Sie Ihre Codebasis auf:

  • java.lang.SecurityManager — vollständig entfernt. Falls eine Extension ihn nutzt (selten in Commerce Cloud, aber prüfen Sie Drittanbieter-Bibliotheken), muss sie umgeschrieben werden.
  • java.util.Date / Calendar-Konstruktoren — einige deprecated Konstruktoren entfernt. Verwenden Sie stattdessen java.time.*.
  • Thread.stop(), Thread.suspend(), Thread.resume() — entfernt. Diese waren immer gefährlich; falls Code sie verwendet, war er ohnehin schon fehlerhaft.
  • Illegal Reflective Access: Das --illegal-access=permit-Flag existiert nicht mehr. Bibliotheken, die auf JDK-Interna zugreifen (sun.misc.Unsafe etc.), müssen ordnungsgemässe APIs verwenden oder explizite --add-opens-Flags hinzufügen.

Führen Sie diese Prüfung sofort auf Ihrer Codebasis durch:

# Nutzung von entferntem SecurityManager finden
grep -rn "SecurityManager" --include="*.java" src/

# Illegal Reflective Access Patterns finden
grep -rn "sun\.misc\|sun\.reflect\|com\.sun\.proxy" --include="*.java" src/

# Deprecated Date-Konstruktoren finden
grep -rn "new Date(" --include="*.java" src/

OpenRewrite: 80 % der Arbeit automatisieren

OpenRewrite ist ein automatisiertes Code-Refactoring-Tool, das Transformationen auf AST-Ebene anwendet. Es versteht Java-Quellcode als Syntaxbaum, nicht als Text — daher behandelt es Imports, vollqualifizierte Namen und Typreferenzen korrekt.

SAP hat Commerce-Cloud-spezifische OpenRewrite-Rezepte veröffentlicht. So richten Sie sie ein.

Schritt 1: OpenRewrite-Plugin hinzufügen

In Ihrer Root build.gradle (oder der Build-Datei für Ihre Custom Extensions):

plugins {
    id 'org.openrewrite.rewrite' version '7.3.0'
}

dependencies {
    rewrite platform('org.openrewrite.recipe:rewrite-recipe-bom:3.5.0')
    rewrite 'org.openrewrite.recipe:rewrite-migrate-java'
    rewrite 'org.openrewrite.recipe:rewrite-spring'
}

rewrite {
    activeRecipe(
        'org.openrewrite.java.migrate.UpgradeToJava21',
        'org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_2',
        'org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta'
    )
}

Schritt 2: Zuerst einen Dry Run ausführen

Prüfen Sie immer die Änderungen, bevor Sie sie anwenden:

./gradlew rewriteDryRun

Dies generiert einen Diff-Bericht in build/reports/rewrite/. Prüfen Sie ihn. Suchen Sie nach False Positives. Achten Sie auf Änderungen in Dateien, die Ihnen nicht gehören (Plattform-Klassen, die nicht modifiziert werden sollten).

Schritt 3: Migration anwenden

./gradlew rewriteRun

Dies modifiziert Ihre Quelldateien in-place. Committen Sie das Ergebnis als einzelnen «Namespace-Migration»-Commit, damit Sie sauber prüfen und bei Bedarf revertieren können.

Schritt 4: Spring-Security-Rezept separat ausführen

Spring-Security-Änderungen sind komplexer als Namespace-Umbenennungen. Führen Sie das dedizierte Rezept aus:

# Zu Ihrem Rewrite-Block hinzufügen
rewrite {
    activeRecipe(
        'org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2'
    )
}

Prüfen Sie die Ausgabe sorgfältig. Das Spring-Security-Rezept behandelt die Entfernung des WebSecurityConfigurerAdapter und Methoden-Umbenennungen, aber es generiert manchmal Code, der kompiliert, aber nicht Ihrer beabsichtigten Sicherheitssemantik entspricht. Verifizieren Sie jede sicherheitsrelevante Änderung manuell.

Was OpenRewrite abdeckt

  • javax.* zu jakarta.* Imports (alle Pakete)
  • Entfernung des Spring-Security-Adapters und Lambda-DSL-Migration
  • antMatchers() zu requestMatchers() Umbenennungen
  • Hibernate @Type-Annotations-Updates
  • Java-21-API-Ersetzungen (deprecated-Methoden-Swaps)
  • Spring-MVC-Methodensignatur-Updates

Was OpenRewrite übersieht

OpenRewrite operiert auf AST-Mustern. Es versteht Ihre Geschäftslogik nicht. Folgendes erfordert manuelle Arbeit:

  • String-basierte Klassenreferenzen: Class.forName("javax.servlet.Filter") wird nicht erkannt
  • XML-Konfigurationsdateien: Spring-XML-Beans, die javax.*-Klassen referenzieren
  • Properties-Dateien: Alle javax.*-Referenzen in .properties oder .yml
  • Reflection-basiertes Laden von Typen: Dynamische Class-Loading-Patterns
  • Benutzerdefinierte Annotation-Prozessoren: Falls Sie eigene Prozessoren geschrieben haben, die javax.*-Annotationen inspizieren

Was OpenRewrite nicht reparieren kann

Die 20 %, die nach dem automatisierten Tooling übrig bleiben, sind der Teil, wo erfahrene Entwickler ihr Können zeigen.

Benutzerdefinierte Spring-Konfigurationen. Wenn Ihr Commerce-Cloud-Projekt XML-basierte Spring-Konfigurationen nutzt (immer noch üblich in älteren Extensions), transformiert OpenRewrite <bean class="javax.servlet.…">-Referenzen nicht zuverlässig. Sie müssen jede *-spring.xml- und *-beans.xml-Datei manuell durchsuchen.

# javax-Referenzen in Spring-XML-Configs finden
grep -rn "javax\." --include="*-spring.xml" --include="*-beans.xml" src/

AOP-Patterns. Wenn Ihre Extensions Spring AOP mit Pointcut-Ausdrücken verwenden, die javax.*-Typen referenzieren, sind diese typischerweise als Strings in @Pointcut- oder @Around-Annotationen gespeichert. OpenRewrite parst sie als Strings, nicht als Typreferenzen. Manuell aktualisieren:

Vorher:

@Around("execution(* javax.servlet.http.HttpServlet+.do*(..))")

Nachher:

@Around("execution(* jakarta.servlet.http.HttpServlet+.do*(..))")

Reflection-basierter Code. Commerce-Cloud-Extensions, die Reflection nutzen, um Entity-Typen zu inspizieren, Spring-Beans dynamisch zu laden oder Proxy-Objekte zu erstellen, können hardcodierte javax.*-Strings enthalten. Diese kompilieren einwandfrei, scheitern aber zur Laufzeit.

Drittanbieter-Bibliotheken. Eine häufige Falle: Ihr Projekt hängt von einer Bibliothek ab, die eigene javax.*-Klassen mitbringt. Nach der Migration haben Sie sowohl javax.servlet als auch jakarta.servlet auf dem Classpath. Das verursacht ClassCastException zur Laufzeit — ein jakarta.servlet.http.HttpServletRequest ist kein javax.servlet.http.HttpServletRequest, obwohl sie identische Methoden haben. Entfernen oder aktualisieren Sie das betreffende JAR.

SAP Commerce Interceptors und dynamisches Typsystem. Das hybris-Typsystem verwendet ein eigenes Interceptor-Framework. Wenn Ihre Interceptors javax.*-Typen über generische Parameter oder Methodensignaturen referenzieren, brauchen sie eine manuelle Prüfung. Das gilt besonders für PrepareInterceptor-, ValidateInterceptor- und LoadInterceptor-Implementierungen, die JPA-annotierte Attribute verarbeiten.

Teststrategie

Die Migration erzeugt eine einzigartige Testherausforderung: Tausende von Dateiänderungen, die meisten davon mechanisch, aber mit einigen semantischen Änderungen, die im Rauschen versteckt sind. Ihre Teststrategie muss die semantischen Probleme finden, ohne im Volumen zu ertrinken.

Unit Tests

Führen Sie zuerst Ihre bestehende Unit-Test-Suite aus. Das ist Ihre schnellste Feedback-Schleife.

./gradlew test

Beheben Sie zuerst Kompilierungsfehler — diese stammen von übersehenen Namespace-Änderungen. Dann beheben Sie Assertion-Fehler — diese stammen von Verhaltensänderungen in Spring 6 oder Hibernate 6.

Rechnen Sie damit, dass ungefähr 5–15 % der Unit-Tests aktualisiert werden müssen, hauptsächlich wegen:

  • Geändertem Mock-Setup (Spring-Security-Mocking-APIs haben sich geändert)
  • Hibernate-Query-Ergebnistyp-Änderungen
  • Änderungen an der Spring-Test-Context-Konfiguration

Integrationstests

Commerce-Cloud-Integrationstests, die @SpringBootTest oder das hybris-Test-Framework nutzen, decken Probleme auf, die Unit-Tests übersehen:

  • Fehler beim Spring-Bean-Wiring (falsche Typen nach Namespace-Änderung)
  • Fehlkonfiguration der Security-Filterkette
  • JPA-Entity-Mapping-Fehler mit Hibernate 6

Führen Sie die vollständige Integrationssuite gegen eine lokale Commerce-Cloud-Installation aus, die Java 21 nutzt:

ant alltests -Dtestclasses.packages=com.yourcompany.*

Performance-Regression

Die Virtual Threads und GC-Verbesserungen von Java 21 sollten die Performance verbessern, nicht verschlechtern. Verifizieren Sie trotzdem:

  1. Startzeit: Vergleichen Sie Kaltstartzeiten zwischen Java-17- und Java-21-Builds
  2. Speicherverbrauch: Überwachen Sie die Heap-Nutzung unter Last — das Typsystem von Hibernate 6 benötigt etwas mehr Metadaten-Speicher
  3. Durchsatz: Führen Sie Ihre Standard-Lasttestszenarien durch und vergleichen Sie die Antwortzeiten
  4. GC-Verhalten: Generational ZGC von Java 21 ist jetzt produktionsreif — erwägen Sie den Wechsel von G1GC, wenn Ihr Workload latenzempfindlich ist

SAP-spezifische Testframeworks

  • ImpEx-Import-Tests: Verifizieren Sie, dass alle ImpEx-Dateien korrekt importieren — besonders solche, die Java-Klassennamen referenzieren
  • Backoffice-Validierung: Melden Sie sich im Backoffice an und prüfen Sie, ob benutzerdefinierte Typen, Editoren und Widgets korrekt dargestellt werden
  • Storefront-Smoke-Tests: Gehen Sie den kritischen Kaufpfad durch — Warenkorb, Checkout, Zahlung, Bestellbestätigung
  • OCC-API-Tests: Testen Sie Ihre Custom-OCC-Endpunkte und verifizieren Sie, dass sich die Request/Response-Verträge nicht geändert haben

Schritt-für-Schritt Migrationsprozedur

Hier ist die Reihenfolge, der wir folgen. Zehn Schritte, in dieser Reihenfolge. Keinen überspringen.

Schritt 1: Custom Code inventarisieren. Zählen Sie Ihre Custom Extensions, Java-Codezeilen, Spring-XML-Dateien und Drittanbieter-Abhängigkeiten. So kennen Sie den Umfang.

# Java-Dateien und Zeilen zählen
find . -name "*.java" -path "*/src/*" | wc -l
find . -name "*.java" -path "*/src/*" -exec cat {} \; | wc -l

# Spring-XML-Configs zählen
find . -name "*-spring.xml" -o -name "*-beans.xml" | wc -l

# Drittanbieter-JARs auflisten
find . -name "*.jar" -path "*/lib/*" | sort

Schritt 2: Migrationsbranch erstellen. Erstellen Sie einen dedizierten Branch. Diese Migration wird Hunderte von Dateien berühren — Sie wollen saubere Trennung von Feature-Arbeit.

git checkout -b migration/java21-spring6

Schritt 3: Build-Tools aktualisieren. Stellen Sie sicher, dass Gradle (oder Ant/Maven, je nach Ihrem Setup) Java 21 unterstützt. Aktualisieren Sie das JDK in Ihrer Build-Umgebung und CI-Pipeline.

Schritt 4: OpenRewrite-Namespace-Migration ausführen. Wenden Sie die Rezepte JavaxMigrationToJakarta und UpgradeToJava21 an. Committen Sie das Ergebnis.

Schritt 5: OpenRewrite Spring-6-Migration ausführen. Wenden Sie die Spring-Framework- und Spring-Security-Rezepte an. Separat prüfen und committen.

Schritt 6: Beheben, was OpenRewrite übersehen hat. Grep nach verbleibenden javax.*-Referenzen in XML, Properties und String-Literalen. Manuell korrigieren. Committen.

# ALLE verbleibenden javax-Referenzen finden
grep -rn "javax\." --include="*.xml" --include="*.properties" \
  --include="*.yml" --include="*.java" src/

Schritt 7: Kompilierungsfehler beheben. Bauen Sie das Projekt und arbeiten Sie jeden Kompilierungsfehler durch. Typisch sind Spring-Security-API-Änderungen, Hibernate-Typsystem-Änderungen oder entfernte Java-APIs.

./gradlew compileJava 2>&1 | grep "error:" | head -50

Schritt 8: Unit-Tests ausführen. Fehler beheben. Methodisch. Korrigieren Sie Tests, die wegen API-Änderungen fehlschlagen, nicht indem Sie sie löschen.

Schritt 9: Integrationstests auf einer Java-21-Umgebung ausführen. Deployen Sie auf eine SAP-Commerce-Cloud-Staging-Umgebung mit Java 21. Führen Sie die vollständige Integrations- und Smoke-Test-Suite aus.

Schritt 10: Performance-Validierung und Produktions-Deployment. Führen Sie Lasttests durch, vergleichen Sie die Metriken mit Ihrer Java-17-Baseline und deployen Sie vor dem 30. Juni in die Produktion.

Häufige Stolperfallen

Aus echten Projekten, die wir gesehen oder betreut haben — die Probleme, die Teams Tage statt Stunden kosten.

ClassNotFoundException zur Laufzeit. Alles kompiliert, aber eine Spring-Bean schlägt beim Starten fehl, weil eine XML-Konfiguration immer noch javax.servlet.Filter als String referenziert. Das verursacht keinen Kompilierungsfehler. Es verursacht eine ClassNotFoundException zur Laufzeit, wenn Spring versucht, die Bean zu instanziieren. Durchsuchen Sie immer XML-Dateien.

Spring Security erlaubt stillschweigend alle Anfragen. Beim Wechsel von WebSecurityConfigurerAdapter zu SecurityFilterChain ist ein häufiger Fehler, .build() am Ende der Kette zu vergessen oder die Bean zu definieren, ohne die Klasse mit @Configuration zu annotieren. Das Ergebnis: Spring lädt seine Standard-Security-Konfiguration, die je nach Classpath alles erlauben oder alles verweigern kann. Testen Sie Authentifizierung und Autorisierung explizit.

Hibernate-Schema-Validierungsfehler. Hibernate 6 ist strikter bei der Schema-Validierung beim Start. Wenn Ihre hybris-Datenbankspalten nicht exakt zu den JPA-Annotationen passen (z.B. eine VARCHAR(255)-Spalte mit @Column(length = 100)), wirft Hibernate 6 eine SchemaManagementException, wo Hibernate 5 den Unterschied stillschweigend ignorierte. Prüfen Sie Ihr Typsystem und Datenbankschema gemeinsam.

Drittanbieter-JAR-Hölle. Eine häufige Falle: Ihr Projekt hängt von einer Bibliothek ab, die eigene javax.*-Klassen bündelt. Nach der Migration haben Sie sowohl javax.servlet als auch jakarta.servlet auf dem Classpath. Das verursacht ClassCastException zur Laufzeit — ein jakarta.servlet.http.HttpServletRequest ist kein javax.servlet.http.HttpServletRequest, auch wenn sie identische Methoden haben. Entfernen oder aktualisieren Sie das betreffende JAR.

ImpEx-Klassenreferenzen. ImpEx-Dateien können Java-Klassen für benutzerdefinierte Translatoren und Import-Prozessoren referenzieren. Wenn diese Klassen im javax.*-Namespace waren (unwahrscheinlich, aber möglich bei benutzerdefinierten Interceptors), schlägt der ImpEx-Import stillschweigend fehl oder mit einer kryptischen Fehlermeldung. Prüfen Sie Ihre ImpEx-Dateien.

Build-Pipeline Java-Versionskonflikt. Ihre lokale Maschine läuft Java 21. Die CI-Pipeline nutzt noch Java 17. Lokal funktioniert alles, das Deployment schlägt fehl. Aktualisieren Sie Ihre CI-Konfiguration — Jenkinsfile, manifest.yml oder .github/workflows/*.yml — um Java 21 anzugeben, bevor Sie den ersten Deployment-Versuch starten.


Die Java-21- und Spring-6-Migration ist mechanischer Natur, aber breit im Umfang. Das automatisierte Tooling ist wirklich gut — OpenRewrite übernimmt die mühsame Namespace-Migration zuverlässig. Was bleibt, ist die sorgfältige Engineering-Arbeit: Spring-Security-Umbauten, Hibernate-6-Kompatibilität, Reflection-basierter Code und gründliches Testen.

Starten Sie jetzt. Die Deadline bewegt sich nicht.

Brauchen Sie Hilfe bei der Einschätzung des Migrationsumfangs Ihres Commerce-Cloud-Projekts? Nehmen Sie Kontakt auf — wir haben das bereits mit mehreren Commerce-Cloud-Projekten durchlaufen und können Ihnen genau sagen, wo die Schmerzpunkte in Ihrer Codebasis liegen. Entdecken Sie auch unsere SAP Commerce Cloud Lösungen für das Gesamtbild unserer Plattform-Arbeit.

SAP Commerce CloudJava 21Spring 6MigrationDeveloper GuideOpenRewrite
Nächster Schritt

Lösungen für E-Commerce

Erfahren Sie, wie SAP Commerce Cloud Ihr Unternehmen voranbringen kann.

Verwandte Artikel

Experten fragen