Aller au contenu
Migration Java 21 + Spring 6 de SAP Commerce Cloud : guide du développeur
Implementation · Publié pour la première fois le ·Mis à jour le par Cyrill Pedol ·12 min de lecture

Migration Java 21 + Spring 6 de SAP Commerce Cloud : guide du développeur

Cyrill Pedol

Cyrill Pedol

SAP Commerce Lead, Spadoom AG

Partager

En septembre 2025, SAP a publié le framework update 2211-jdk21 pour SAP Commerce Cloud : depuis, la plateforme tourne sur Java 21 et Spring Framework 6 (SAP Help Portal : Framework Update). Deux dates en ont découlé. Les correctifs de sécurité des mises à jour 2211 basées sur Java 17 ont couru jusqu’à fin juin 2026. Et, selon l’annonce de SAP, les nouveaux builds ciblant Java 17 sont bloqués après le 31 août 2026.

Ces deux dates sont passées. Si votre projet a déjà basculé, ce guide vous aide à vérifier ce qui pourrait encore traîner. Sinon, il y a urgence : sans la mise à jour, vous ne pouvez plus construire ni déployer de modifications.

La mise à jour est plus qu’un changement de JDK. Spring 6 apporte le namespace Jakarta EE : javax.servlet, javax.validation et javax.annotation, les imports que les développeurs écrivent depuis quinze ans, deviennent jakarta.*. Cela touche les servlets, les filtres, les annotations de validation, la configuration Spring Security et potentiellement chaque extension spécifique. Les outils font l’essentiel du travail mécanique ; le reste relève de la véritable ingénierie.

En bref : avec 2211-jdk21, SAP Commerce Cloud tourne sur Java 21 et Spring 6. Les correctifs de sécurité pour Java 17 ont pris fin en juin 2026, et les nouveaux builds Java 17 sont bloqués après le 31 août 2026. La migration consiste à passer de javax.* à jakarta.*, à réécrire les configurations Spring Security avec SecurityFilterChain, à vérifier les définitions XML de beans, la réflexion et les bibliothèques tierces, puis à tester à fond. OpenRewrite automatise l’essentiel du travail sur le namespace. Prévoyez deux à quatre semaines de migration et deux à trois semaines de tests de non-régression.

Ce qui change et pourquoi

Trois changements interviennent en même temps. Ils sont liés, mais ils cassent des choses différentes.

De Java 17 à Java 21. La version 2211, la génération exclusivement cloud de Commerce Cloud, a relevé le minimum à Java 17 ; 2211-jdk21 passe à Java 21, version à support long terme depuis septembre 2023 (OpenJDK). Java 21 apporte les virtual threads, le pattern matching pour switch, les record patterns et les sequenced collections. L’essentiel est additif et ne casse pas le code existant. Ce qui casse, c’est le code qui s’appuie par réflexion sur des éléments internes du JDK ou sur des API dont le comportement a changé.

De Spring 5 à Spring 6. Spring Framework 6 exige Java 17 ou plus et repose sur les API Jakarta EE 9+ (notes de migration vers Spring Framework 6). C’est le gros morceau : Spring 6 ne prend plus en charge le namespace javax.*. Si votre code étend des classes Spring ou implémente des interfaces qui référencent des types javax.*, il ne compile plus.

Le namespace Jakarta. Après la cession de Java EE par Oracle à l’Eclipse Foundation, les paquets ont été renommés de javax.* en jakarta.*. Un changement mécanique, mais omniprésent : chaque import, chaque nom de classe complet dans le XML, chaque référence sous forme de chaîne.

La manière dont ces changements s’insèrent dans l’architecture de Commerce Cloud est expliquée dans notre vue d’ensemble de SAP Commerce Cloud. Les autres nouveautés livrées par SAP cette année sont résumées dans les mises à jour pratiques de septembre 2026.

La chronologie

Date Événement
Septembre 2023 Sortie de Java 21 en version LTS
Septembre 2025 SAP publie le framework update 2211-jdk21 (Java 21, Spring 6)
Fin juin 2026 Fin des correctifs de sécurité des mises à jour 2211 basées sur Java 17
31 août 2026 Les nouveaux builds ciblant Java 17 sont bloqués

La plupart des projets Commerce Cloud comptent des dizaines de milliers de lignes de Java spécifique réparties dans des dizaines d’extensions. Le seul changement de namespace produit des milliers de fichiers modifiés, et les tests prennent plus de temps que la migration elle-même.

Où vous en êtes en septembre 2026 : si vous êtes encore sur une version 2211 avec Java 17, vous travaillez sans correctifs de sécurité et ne pouvez plus livrer de modifications. Placez la migration en tête de votre feuille de route, gelez le développement de fonctionnalités et suivez la procédure ci-dessous. Vérifiez les règles actuellement en vigueur dans la documentation SAP et auprès du support SAP avant de planifier.

Checklist des changements incompatibles

Classés à peu près par fréquence et par impact.

Migration du namespace de javax.* vers jakarta.*

Le changement le plus répandu. Chaque référence à ces paquets doit être mise à jour :

Ancien (javax.*) Nouveau (jakarta.*) Code concerné
javax.servlet.* jakarta.servlet.* Filtres, contrôleurs spécifiques, wrappers de requête/réponse
javax.validation.* jakarta.validation.* Bean validation, @NotNull, @Size, validateurs spécifiques
javax.annotation.* jakarta.annotation.* @PostConstruct, @PreDestroy, @Resource
javax.inject.* jakarta.inject.* @Inject, @Named
javax.persistence.* jakarta.persistence.* Uniquement là où le code spécifique utilise JPA directement
javax.ws.rs.* jakarta.ws.rs.* Points de terminaison JAX-RS (s’il y en a)

Avant :

import javax.servlet.http.HttpServletRequest;
import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;

public class CustomRequestValidator {
    @NotNull
    private String customField;

    @PostConstruct
    public void init() { /* ... */ }
}

Après :

import jakarta.servlet.http.HttpServletRequest;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.NotNull;

public class CustomRequestValidator {
    @NotNull
    private String customField;

    @PostConstruct
    public void init() { /* ... */ }
}

C’est surtout du rechercher-remplacer, mais attention aux chaînes littérales et aux fichiers XML où javax. apparaît comme nom complet. OpenRewrite en trouve la plupart ; un grep manuel trouve le reste.

Changements dans Spring Security

Spring Security 6 introduit plusieurs changements incompatibles qui touchent les projets Commerce Cloud. Le plus important : WebSecurityConfigurerAdapter a disparu.

Avant (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();
    }
}

Après (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();
    }
}

Les principaux changements :

  • WebSecurityConfigurerAdapter est supprimé ; on utilise des beans SecurityFilterChain
  • authorizeRequests() devient authorizeHttpRequests()
  • antMatchers() devient requestMatchers()
  • csrf(), cors() et sessionManagement() se configurent via la DSL lambda
  • Le SecurityContext n’est plus enregistré automatiquement dans la session ; la persistance est explicite

Les configurations Spring Security spécifiques pour l’authentification sur la vitrine, la connexion B2B ou l’accès au Backoffice doivent être réécrites à la main. Il en va de même pour les extensions fondées sur l’ancien projet Spring Security OAuth, arrivé en fin de vie en 2022 : vérifiez dans la documentation SAP du framework update comment l’authentification OCC est désormais gérée avant de porter quoi que ce soit.

Changements dans Spring MVC

Spring 6 a supprimé plusieurs schémas dépréciés en 5.x :

  • CommonsMultipartResolver est remplacé par StandardServletMultipartResolver. Si vous avez configuré un téléversement de fichiers spécifique, mettez à jour le bean du resolver.
  • La correspondance avec barre oblique finale est désactivée par défaut. /api/products/ et /api/products sont désormais des routes différentes. Si la vitrine ou des clients d’API dépendent de l’ancienne tolérance, ajoutez des mappings explicites ou une redirection, et corrigez les URL.
  • La correspondance de chemins utilise par défaut PathPatternParser, plus strict que AntPathMatcher pour certains motifs. Testez les mappings de vos contrôleurs spécifiques.

Là où le code spécifique utilise JPA ou Hibernate

SAP Commerce persiste les données via son propre système de types et sa couche de services, pas via JPA. Cette section ne concerne que les extensions qui embarquent leur propre pile JPA ou Hibernate, par exemple pour une base de données séparée. Pour elles, le passage à Jakarta signifie Hibernate 6, avec ses propres changements :

  • Génération d’identifiants par séquence par défaut. Si vous comptez sur l’auto-incrément, définissez explicitement strategy = GenerationType.IDENTITY.
  • Système de types remanié. Les implémentations spécifiques de UserType doivent être mises à jour ; l’interface a changé de signature générique.
  • Annotation @Type modifiée. @Type(type = "yes_no") devient un convertisseur :

Avant :

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

Après :

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

Changements du JDK entre 17 et 21

Vérifiez votre code et vos bibliothèques pour :

  • java.lang.SecurityManager : promis à la suppression depuis Java 17 (JEP 411) et inutilisable par défaut. Le code qui en installe un échoue à l’exécution.
  • Thread.stop(), Thread.suspend(), Thread.resume() : lèvent désormais une UnsupportedOperationException. Ils ont toujours été dangereux ; le code qui les appelle était déjà défectueux.
  • Encapsulation forte des éléments internes du JDK : les accès par réflexion à des paquets internes (sun.misc, sun.reflect et d’autres) échouent sans options --add-opens explicites. Mieux vaut mettre à jour la bibliothèque qu’ajouter des options.
  • Finalisation : promise à la suppression. Remplacez finalize() par Cleaner ou try-with-resources.

Lancez ces vérifications tôt :

# Trouver les usages de SecurityManager
grep -rn "SecurityManager" --include="*.java" .

# Trouver les accès par réflexion aux éléments internes du JDK
grep -rn "sun\.misc\|sun\.reflect\|com\.sun\.proxy" --include="*.java" .

# Trouver les méthodes de contrôle de threads supprimées
grep -rn "\.stop()\|\.suspend()\|\.resume()" --include="*.java" .

OpenRewrite : automatiser l’essentiel du travail

OpenRewrite est un outil de refactoring automatique qui travaille sur l’arbre syntaxique et non sur le texte ; il traite donc correctement les imports, les noms complets et les références de types. C’est devenu l’outil de référence pour ce type de migration. Les recettes open source ci-dessous couvrent les parties génériques Java, Jakarta et Spring ; pour d’éventuels outils propres à Commerce, consultez la documentation SAP du framework update.

Étape 1 : ajouter le plugin OpenRewrite

SAP Commerce se construit avec Ant. Le plus simple pour exécuter OpenRewrite est un petit wrapper Gradle (ou Maven) qui pointe vers les dossiers sources de vos extensions spécifiques :

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'
    )
}

Les recettes sont documentées sous UpgradeToJava21, JavaxMigrationToJakarta et UpgradeSpringFramework_6_2. Utilisez des versions à jour du plugin et du BOM.

Étape 2 : lancer d’abord un essai à blanc

./gradlew rewriteDryRun

Un rapport des différences est écrit dans build/reports/rewrite/. Examinez-le, cherchez les faux positifs et les modifications de fichiers qui ne vous appartiennent pas.

Étape 3 : appliquer la migration

./gradlew rewriteRun

Enregistrez le résultat dans un seul commit « migration du namespace », afin de pouvoir le relire et l’annuler proprement.

Étape 4 : exécuter séparément la recette Spring Security

rewrite {
    activeRecipe(
        'org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2'
    )
}

La recette Spring Security gère la suppression de l’adaptateur et les renommages, mais produit parfois du code qui compile sans respecter la logique de sécurité voulue. Vérifiez à la main chaque modification liée à la sécurité.

Ce que couvre OpenRewrite

  • Imports de javax.* vers jakarta.*
  • Suppression de l’adaptateur Spring Security et passage à la DSL lambda
  • Renommage de antMatchers() en requestMatchers()
  • Mise à jour de l’annotation Hibernate @Type (là où JPA est utilisé)
  • Remplacement d’API pour Java 21
  • Mise à jour des signatures Spring MVC

Ce qu’OpenRewrite manque

  • Références de classes sous forme de chaîne : Class.forName("javax.servlet.Filter")
  • Configuration XML : définitions de beans Spring dans *-spring.xml et *-beans.xml qui référencent des classes javax.*
  • Fichiers properties : références javax.* dans les fichiers .properties
  • Chargement de types par réflexion : chargement dynamique de classes
  • Processeurs d’annotations spécifiques qui analysent des annotations javax.*

Ce qu’OpenRewrite ne peut pas corriger

C’est ici que les développeurs expérimentés font la différence.

Configurations Spring XML. Les extensions Commerce définissent de nombreux beans en XML. OpenRewrite ne transforme pas de façon fiable les références <bean class="javax.servlet.…">, alors passez chaque fichier Spring XML au crible :

# Trouver les références javax dans les configs Spring XML
grep -rn "javax\." --include="*-spring.xml" --include="*-beans.xml" .

Schémas AOP. Les expressions pointcut dans @Pointcut ou @Around sont des chaînes, pas des références de types :

Avant :

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

Après :

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

Code fondé sur la réflexion. Les extensions qui inspectent des types, chargent des beans dynamiquement ou créent des proxys peuvent contenir des chaînes javax.* codées en dur. Elles compilent et échouent à l’exécution.

Bibliothèques tierces. Si une extension dépend d’un JAR qui n’est pas encore passé à Jakarta EE, mettez-le à jour ou remplacez-le. Les JAR passerelles sont au mieux une solution transitoire.

Intercepteurs et système de types. Relisez les implémentations de PrepareInterceptor, ValidateInterceptor et LoadInterceptor, ainsi que tout code qui utilise des annotations de validation ou des types servlet dans ses signatures.

Stratégie de test

La migration produit des milliers de changements mécaniques parmi lesquels se cachent quelques changements de fond. La stratégie de test doit les trouver sans se noyer dans le volume.

Tests unitaires

Lancez d’abord les tests unitaires existants : c’est le retour le plus rapide, et à ce stade ils trouvent plus de vraies régressions qu’une relecture de code attentive. Corrigez d’abord les erreurs de compilation (changements de namespace oubliés), puis les échecs d’assertion (changements de comportement dans Spring 6).

Les tests doivent généralement être adaptés en raison :

  • d’une configuration des mocks modifiée (les API de test de Spring Security ont changé)
  • de changements dans la configuration du contexte de test Spring
  • d’une correspondance de chemins plus stricte dans les tests MVC

Tests d’intégration

Exécutez la suite d’intégration complète sur une installation locale en Java 21 :

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

Ils révèlent ce que les tests unitaires ne voient pas : des erreurs de câblage des beans après le changement de namespace, des chaînes de filtres de sécurité mal configurées et des ClassNotFoundException à l’exécution provenant du XML.

Régression des performances

Java 21 devrait améliorer les performances, mais vérifiez :

  1. Temps de démarrage : comparez les démarrages à froid entre les builds Java 17 et Java 21
  2. Empreinte mémoire : surveillez l’utilisation du tas sous charge
  3. Débit : lancez vos tests de charge habituels et comparez les temps de réponse
  4. Ramasse-miettes : ZGC générationnel est disponible en Java 21 ; évaluez-le pour les charges sensibles à la latence avant de basculer

Vérifications propres à SAP

  • Imports ImpEx : vérifiez que tous les fichiers ImpEx s’importent encore, en particulier ceux qui référencent des classes Java
  • Backoffice : contrôlez que les types, éditeurs et widgets spécifiques s’affichent correctement
  • Tests de fumée de la vitrine : panier, checkout, paiement, confirmation de commande
  • Tests des API OCC : appelez vos points de terminaison OCC spécifiques et vérifiez les contrats de requête et de réponse, authentification comprise

La migration étape par étape

Dix étapes, dans cet ordre.

Étape 1 : inventorier le code spécifique. Comptez les extensions spécifiques, les lignes de Java, les fichiers Spring XML et les dépendances tierces.

# Compter les fichiers Java et les lignes
find . -name "*.java" -path "*/src/*" | wc -l
find . -name "*.java" -path "*/src/*" -exec cat {} \; | wc -l

# Compter les configs Spring XML
find . -name "*-spring.xml" -o -name "*-beans.xml" | wc -l

# Lister les JAR tiers
find . -name "*.jar" -path "*/lib/*" | sort

Étape 2 : créer une branche de migration. La migration touche des centaines de fichiers ; séparez-la du développement de fonctionnalités.

git checkout -b migration/java21-spring6

Étape 3 : mettre à jour le build. Passez le JDK local et la CI à Java 21, et réglez commerceSuiteVersion dans le manifest.json sur une version 2211-jdk21 actuelle.

Étape 4 : migration du namespace avec OpenRewrite. Appliquez JavaxMigrationToJakarta et UpgradeToJava21, puis faites un commit.

Étape 5 : exécuter les recettes Spring 6. Appliquez les recettes Spring Framework et Spring Security, relisez-les et faites un commit séparé.

Étape 6 : corriger ce qu’OpenRewrite a manqué. Cherchez les références javax. restantes dans le XML, les properties et les chaînes littérales.

# Trouver TOUTES les références javax restantes
grep -rn "javax\." --include="*.xml" --include="*.properties" \
  --include="*.java" .

Étape 7 : corriger les erreurs de compilation. Construisez et traitez chaque erreur ; en général des changements d’API Spring Security, des comportements du JDK supprimés ou des bibliothèques obsolètes.

Étape 8 : lancer les tests unitaires et corriger les échecs. Réparez les tests qui échouent à cause de changements d’API ; ne les supprimez pas.

Étape 9 : tests d’intégration sur un environnement Java 21. Déployez sur un environnement de préproduction Commerce Cloud en 2211-jdk21 et lancez la suite complète de tests d’intégration et de fumée.

Étape 10 : valider les performances et passer en production. Lancez les tests de charge, comparez avec la référence Java 17 et déployez.

Pièges fréquents

ClassNotFoundException à l’exécution. Tout compile, mais un bean Spring échoue au démarrage parce qu’une configuration XML référence encore javax.servlet.Filter sous forme de chaîne. Passez toujours les fichiers XML au crible.

Spring Security laisse tout passer (ou rien). Lors du passage de WebSecurityConfigurerAdapter à SecurityFilterChain, un .build() manquant ou un @Configuration oublié fait retomber Spring sur une configuration par défaut. Testez explicitement l’authentification et les autorisations.

Conflits de JAR tiers. D’après notre expérience, c’est le piège qui coûte le plus de jours. Une bibliothèque embarque ses propres classes javax.* et, après la migration, javax.servlet et jakarta.servlet se retrouvent tous deux dans le classpath. Résultat : une ClassCastException à l’exécution, car un jakarta.servlet.http.HttpServletRequest n’est pas un javax.servlet.http.HttpServletRequest, même si les méthodes sont identiques. Retirez ou mettez à jour le JAR en cause.

Références de classes dans les ImpEx. Les fichiers ImpEx peuvent référencer des classes Java pour des traducteurs et des processeurs d’import spécifiques. Si ces classes dépendent de types javax.*, l’import échoue avec un message obscur. Vérifiez vos fichiers ImpEx.

Versions divergentes dans le pipeline de build. En local, Java 21 tourne, mais le pipeline de CI ou le manifest.json pointe encore vers une version Java 17. Tout fonctionne en local, le déploiement échoue. Mettez les deux à jour avant la première tentative de déploiement.


La migration vers Java 21 et Spring 6 est mécanique par nature et large par son étendue. OpenRewrite prend en charge de manière fiable le fastidieux travail sur le namespace. Reste le travail d’ingénierie soigné : réécrire Spring Security, les configurations XML, la réflexion, les bibliothèques et des tests approfondis. Si vous prévoyez aussi des changements plus larges de la plateforme, notre checklist de migration pour SAP Commerce couvre le reste du chemin.

Besoin d’aide pour évaluer le périmètre dans votre code ? Contactez-nous. Nous connaissons cette mise à jour par notre propre travail sur Commerce Cloud. Notre façon de travailler avec la plateforme est présentée sur notre page SAP Commerce Cloud, et si vous comparez des partenaires d’implémentation, notre panorama des meilleurs partenaires SAP Commerce Cloud en Suisse vous y aidera.

SAP Commerce CloudJava 21Spring 6MigrationDeveloper GuideOpenRewrite
Ask Spadoom · assistant IA

Demandez à Spadoom

Des réponses fondées sur ce que Spadoom a publié sur ce site, avec des liens vers les pages sources.

Essayez l'une de ces questions

Entrée pour envoyer · Maj+Entrée pour une nouvelle ligne 0 / 600
Poursuivre avec un expert Ouvre le formulaire de contact avec votre question.

Réponses générées par IA. À vérifier avant d'agir. Les questions sont enregistrées de manière anonyme, sans adresse IP, afin d'améliorer nos contenus. Merci de ne pas saisir de données personnelles.

Etape suivante

SAP Commerce Cloud partenaire d'implémentation

Spadoom est le partenaire d'implémentation SAP Commerce Cloud en Suisse, Allemagne, Autriche et Italie. Médiane de go-live de 14 semaines. Clients en production dans tout le DACH.

Articles associes

Implémentation 14 min de lecture

SAP Hybris End of Life : la checklist complète de migration pour 2026

La maintenance principale de SAP Commerce on-premise (anciennement Hybris) a pris fin le 31 juillet 2026. Ce que cela signifie pour vous aujourd'hui, ce qui passe de Hybris à Commerce Cloud et la checklist avec laquelle nous migrons : évaluation, architecture, réalisation, mise en production et les semaines qui suivent.

Cyrill Pedol · 1 avr. 2026
Lire l'article →
Implementation 10 min de lecture

De SAP Hybris à Commerce Cloud en 90 jours : un playbook de migration

Comment une plateforme SAP Hybris de taille moyenne arrive sur SAP Commerce Cloud en 90 jours : 30 jours de préparation, trois sprints, mise en production. La méthode derrière nos lancements commerce les plus rapides, et ce qu'il faut faire maintenant que la maintenance principale de l'on-premise a pris fin.

Cyrill Pedol · 25 févr. 2025
Lire l'article →