Migrazione SAP Commerce Cloud a Java 21 + Spring 6: guida per sviluppatori
SAP Commerce Lead, Spadoom AG
A settembre 2025 SAP ha rilasciato il framework update 2211-jdk21 per SAP Commerce Cloud: da allora la piattaforma funziona su Java 21 e Spring Framework 6 (SAP Help Portal: Framework Update). Ne sono derivate due date. Le correzioni di sicurezza per gli update 2211 basati su Java 17 sono proseguite fino a fine giugno 2026. E, secondo l’annuncio di SAP, le nuove build destinate a Java 17 sono bloccate dopo il 31 agosto 2026.
Entrambe le date sono passate. Se il vostro progetto ha già fatto il passaggio, questa guida vi aiuta a verificare cosa potrebbe ancora nascondersi. Se non l’ha fatto, c’è fretta: senza l’update non potete più compilare e rilasciare modifiche.
L’update è più di un cambio di JDK. Spring 6 porta con sé il namespace Jakarta EE: javax.servlet, javax.validation e javax.annotation, gli import che gli sviluppatori scrivono da quindici anni, diventano jakarta.*. Sono coinvolti servlet, filtri, annotazioni di validazione, la configurazione di Spring Security e potenzialmente ogni extension personalizzata. Gli strumenti fanno gran parte del lavoro meccanico; il resto è vera ingegneria.
In sintesi: con 2211-jdk21 SAP Commerce Cloud funziona su Java 21 e Spring 6. Le correzioni di sicurezza per Java 17 sono terminate a giugno 2026 e le nuove build Java 17 sono bloccate dopo il 31 agosto 2026. La migrazione significa: passare da
javax.*ajakarta.*, riscrivere le configurazioni Spring Security conSecurityFilterChain, verificare definizioni XML dei bean, reflection e librerie di terze parti, poi testare a fondo. OpenRewrite automatizza la maggior parte del lavoro sul namespace. Prevedete da due a quattro settimane di migrazione e da due a tre settimane di test di regressione.
Cosa cambia e perché
Tre cambiamenti avvengono insieme. Sono collegati, ma rompono cose diverse.
Da Java 17 a Java 21. La release 2211, la generazione solo cloud di Commerce Cloud, ha portato il minimo a Java 17; 2211-jdk21 passa a Java 21, release con supporto a lungo termine da settembre 2023 (OpenJDK). Java 21 introduce virtual thread, pattern matching per switch, record pattern e sequenced collection. Per lo più si tratta di aggiunte che non rompono il codice esistente. Si rompe il codice che si appoggia via reflection a parti interne del JDK o ad API il cui comportamento è cambiato.
Da Spring 5 a Spring 6. Spring Framework 6 richiede Java 17 o superiore e si basa sulle API Jakarta EE 9+ (note di upgrade a Spring Framework 6). È il cambiamento più grande: Spring 6 non supporta più il namespace javax.*. Se il vostro codice estende classi Spring o implementa interfacce che fanno riferimento a tipi javax.*, non compila più.
Il namespace Jakarta. Dopo che Oracle ha ceduto Java EE alla Eclipse Foundation, i pacchetti sono stati rinominati da javax.* a jakarta.*. Una modifica meccanica, ma onnipresente: ogni import, ogni nome di classe completo in XML, ogni riferimento in forma di stringa.
Come questi cambiamenti si inseriscono nell’architettura di Commerce Cloud lo spiega la nostra panoramica su SAP Commerce Cloud. Le altre novità rilasciate da SAP quest’anno sono riassunte negli aggiornamenti pratici di settembre 2026.
La cronologia
| Data | Evento |
|---|---|
| Settembre 2023 | Java 21 esce come versione LTS |
| Settembre 2025 | SAP rilascia il framework update 2211-jdk21 (Java 21, Spring 6) |
| Fine giugno 2026 | Terminano le correzioni di sicurezza per gli update 2211 basati su Java 17 |
| 31 agosto 2026 | Le nuove build destinate a Java 17 vengono bloccate |
La maggior parte dei progetti Commerce Cloud contiene decine di migliaia di righe di Java personalizzato distribuite in decine di extension. Il solo cambio di namespace produce migliaia di file modificati, e i test richiedono più tempo della migrazione stessa.
Dove siete a settembre 2026: se siete ancora su una versione 2211 con Java 17, lavorate senza correzioni di sicurezza e non potete più rilasciare modifiche. Mettete la migrazione al primo posto della roadmap, congelate lo sviluppo di funzionalità e seguite la procedura più sotto. Verificate le regole attualmente in vigore nella documentazione SAP e con il supporto SAP prima di pianificare.
Checklist dei breaking change
In ordine approssimativo di frequenza e impatto.
Migrazione del namespace da javax.* a jakarta.*
Il cambiamento più diffuso. Ogni riferimento a questi pacchetti va aggiornato:
| Vecchio (javax.*) | Nuovo (jakarta.*) | Codice interessato |
|---|---|---|
javax.servlet.* |
jakarta.servlet.* |
Filtri, controller personalizzati, wrapper di request/response |
javax.validation.* |
jakarta.validation.* |
Bean validation, @NotNull, @Size, validatori personalizzati |
javax.annotation.* |
jakarta.annotation.* |
@PostConstruct, @PreDestroy, @Resource |
javax.inject.* |
jakarta.inject.* |
@Inject, @Named |
javax.persistence.* |
jakarta.persistence.* |
Solo dove il codice personalizzato usa JPA direttamente |
javax.ws.rs.* |
jakarta.ws.rs.* |
Endpoint JAX-RS (se presenti) |
Prima:
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() { /* ... */ }
}
Dopo:
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() { /* ... */ }
}
In gran parte è un cerca e sostituisci, ma attenzione ai letterali stringa e ai file XML in cui javax. compare come nome completo. OpenRewrite ne trova la maggior parte; un grep manuale trova il resto.
Modifiche a Spring Security
Spring Security 6 introduce diversi breaking change che riguardano i progetti Commerce Cloud. Il più grande: WebSecurityConfigurerAdapter non esiste più.
Prima (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();
}
}
Dopo (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();
}
}
Le modifiche principali:
WebSecurityConfigurerAdapterè rimosso; al suo posto beanSecurityFilterChainauthorizeRequests()diventaauthorizeHttpRequests()antMatchers()diventarequestMatchers()csrf(),cors()esessionManagement()si configurano tramite la DSL lambda- Il
SecurityContextnon viene più salvato automaticamente nella sessione; la persistenza è esplicita
Le configurazioni Spring Security personalizzate per l’autenticazione nello storefront, il login B2B o l’accesso al Backoffice vanno riscritte a mano. Lo stesso vale per le extension basate sul vecchio progetto Spring Security OAuth, arrivato a fine vita nel 2022: verificate nella documentazione SAP del framework update come viene gestita ora l’autenticazione OCC prima di portare qualsiasi cosa.
Modifiche a Spring MVC
Spring 6 ha rimosso diversi schemi deprecati nella 5.x:
CommonsMultipartResolverè sostituito daStandardServletMultipartResolver. Se avete configurato un upload di file personalizzato, aggiornate il bean del resolver.- Il matching con slash finale è disattivato di default.
/api/products/e/api/productssono ora rotte diverse. Se storefront o client API dipendono dalla vecchia tolleranza, aggiungete mapping espliciti o un redirect e correggete gli URL. - Il path matching usa di default
PathPatternParser, più rigoroso diAntPathMatchersu alcuni pattern. Testate i mapping dei controller personalizzati.
Dove il codice personalizzato usa JPA o Hibernate
SAP Commerce salva i dati tramite il proprio type system e il service layer, non tramite JPA. Questa sezione riguarda solo le extension che portano un proprio stack JPA o Hibernate, per esempio per un database separato. Per loro il passaggio a Jakarta significa Hibernate 6, con modifiche proprie:
- Generazione degli ID basata su sequenze come default. Se vi affidate all’auto-increment, impostate esplicitamente
strategy = GenerationType.IDENTITY. - Type system rivisto. Le implementazioni personalizzate di
UserTypevanno aggiornate; l’interfaccia ha cambiato firma generica. - Annotazione
@Typemodificata.@Type(type = "yes_no")diventa un converter:
Prima:
@Type(type = "yes_no")
private Boolean active;
Dopo:
@Convert(converter = org.hibernate.type.YesNoConverter.class)
private Boolean active;
Modifiche del JDK tra 17 e 21
Verificate codice e librerie per:
java.lang.SecurityManager: destinato alla rimozione da Java 17 (JEP 411) e non utilizzabile di default. Il codice che ne installa uno fallisce a runtime.Thread.stop(),Thread.suspend(),Thread.resume(): ora lancianoUnsupportedOperationException. Sono sempre stati pericolosi; il codice che li chiama era già difettoso.- Incapsulamento forte delle parti interne del JDK: gli accessi via reflection a pacchetti interni (
sun.misc,sun.reflecte altri) falliscono se non sono impostati flag--add-opensespliciti. Meglio aggiornare la libreria che aggiungere flag. - Finalization: destinata alla rimozione. Sostituite
finalize()conCleanero try-with-resources.
Eseguite presto questi controlli:
# Trovare utilizzi di SecurityManager
grep -rn "SecurityManager" --include="*.java" .
# Trovare accessi via reflection alle parti interne del JDK
grep -rn "sun\.misc\|sun\.reflect\|com\.sun\.proxy" --include="*.java" .
# Trovare i metodi di controllo dei thread rimossi
grep -rn "\.stop()\|\.suspend()\|\.resume()" --include="*.java" .
OpenRewrite: automatizzare la maggior parte del lavoro
OpenRewrite è uno strumento di refactoring automatico che lavora sull’albero sintattico, non sul testo, e quindi gestisce correttamente import, nomi completi e riferimenti di tipo. È diventato lo strumento standard per questo tipo di migrazione. Le ricette open source qui sotto coprono le parti generiche di Java, Jakarta e Spring; per eventuali strumenti specifici di Commerce consultate la documentazione SAP del framework update.
Passo 1: aggiungere il plugin OpenRewrite
SAP Commerce compila con Ant. Il modo più semplice per eseguire OpenRewrite è un piccolo wrapper Gradle (o Maven) che punta alle cartelle sorgente delle vostre extension personalizzate:
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'
)
}
Le ricette sono documentate in UpgradeToJava21, JavaxMigrationToJakarta e UpgradeSpringFramework_6_2. Usate versioni aggiornate di plugin e BOM.
Passo 2: eseguire prima una prova
./gradlew rewriteDryRun
Viene scritto un report delle differenze in build/reports/rewrite/. Esaminatelo, cercate falsi positivi e modifiche a file che non sono vostri.
Passo 3: applicare la migrazione
./gradlew rewriteRun
Salvate il risultato in un unico commit «migrazione namespace», così che si possa rivedere e annullare in modo pulito.
Passo 4: eseguire separatamente la ricetta Spring Security
rewrite {
activeRecipe(
'org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2'
)
}
La ricetta Spring Security gestisce la rimozione dell’adapter e le ridenominazioni, ma a volte genera codice che compila senza rispettare la logica di sicurezza prevista. Verificate a mano ogni modifica legata alla sicurezza.
Cosa copre OpenRewrite
- Import da
javax.*ajakarta.* - Rimozione dell’adapter di Spring Security e passaggio alla DSL lambda
- Ridenominazione di
antMatchers()inrequestMatchers() - Aggiornamento dell’annotazione Hibernate
@Type(dove si usa JPA) - Sostituzione di API per Java 21
- Aggiornamento delle firme di Spring MVC
Cosa sfugge a OpenRewrite
- Riferimenti a classi sotto forma di stringa:
Class.forName("javax.servlet.Filter") - Configurazione XML: definizioni di bean Spring in
*-spring.xmle*-beans.xmlche fanno riferimento a classijavax.* - File properties: riferimenti
javax.*nei file.properties - Caricamento di tipi via reflection: caricamento dinamico delle classi
- Annotation processor personalizzati che analizzano annotazioni
javax.*
Cosa OpenRewrite non può sistemare
Qui gli sviluppatori esperti si guadagnano lo stipendio.
Configurazioni Spring XML. Le extension Commerce definiscono molti bean in XML. OpenRewrite non trasforma in modo affidabile i riferimenti <bean class="javax.servlet.…">, quindi controllate ogni file Spring XML:
# Trovare riferimenti javax nelle configurazioni Spring XML
grep -rn "javax\." --include="*-spring.xml" --include="*-beans.xml" .
Schemi AOP. Le espressioni pointcut in @Pointcut o @Around sono stringhe, non riferimenti di tipo:
Prima:
@Around("execution(* javax.servlet.http.HttpServlet+.do*(..))")
Dopo:
@Around("execution(* jakarta.servlet.http.HttpServlet+.do*(..))")
Codice basato su reflection. Le extension che ispezionano tipi, caricano bean dinamicamente o creano proxy possono contenere stringhe javax.* scritte nel codice. Compilano e falliscono a runtime.
Librerie di terze parti. Se un’extension dipende da un JAR non ancora passato a Jakarta EE, aggiornatelo o sostituitelo. I JAR ponte sono al massimo una soluzione temporanea.
Interceptor e type system. Rivedete le implementazioni di PrepareInterceptor, ValidateInterceptor e LoadInterceptor e ogni codice che usa annotazioni di validazione o tipi servlet nelle proprie firme.
Strategia di test
La migrazione produce migliaia di modifiche meccaniche, tra cui se ne nascondono alcune sostanziali. La strategia di test deve trovarle senza annegare nel volume.
Test unitari
Eseguite prima i test unitari esistenti: sono il riscontro più rapido e in questa fase trovano più regressioni reali di un’attenta revisione del codice. Correggete prima gli errori di compilazione (modifiche al namespace sfuggite), poi quelli di asserzione (comportamenti cambiati in Spring 6).
Di solito i test vanno adattati per:
- configurazione dei mock cambiata (le API di test di Spring Security sono cambiate)
- modifiche alla configurazione del contesto di test Spring
- path matching più rigoroso nei test MVC
Test di integrazione
Eseguite l’intera suite di integrazione su un’installazione locale con Java 21:
ant alltests -Dtestclasses.packages=com.yourcompany.*
Mostrano ciò che i test unitari non vedono: errori di collegamento dei bean dopo il cambio di namespace, catene di filtri di sicurezza configurate male e ClassNotFoundException a runtime dovute all’XML.
Regressione delle prestazioni
Java 21 dovrebbe migliorare le prestazioni, ma verificate:
- Tempo di avvio: confrontate gli avvii a freddo tra build Java 17 e Java 21
- Uso della memoria: osservate l’uso dell’heap sotto carico
- Throughput: eseguite i test di carico standard e confrontate i tempi di risposta
- Garbage collection: in Java 21 è disponibile ZGC generazionale; valutatelo per i carichi sensibili alla latenza prima di cambiare
Verifiche specifiche SAP
- Import ImpEx: verificate che tutti i file ImpEx vengano ancora importati, soprattutto quelli con riferimenti a classi Java
- Backoffice: controllate che tipi, editor e widget personalizzati vengano visualizzati correttamente
- Smoke test dello storefront: carrello, checkout, pagamento, conferma d’ordine
- Test delle API OCC: chiamate gli endpoint OCC personalizzati e verificate i contratti di richiesta e risposta, autenticazione compresa
Migrazione passo per passo
Dieci passi, in quest’ordine.
Passo 1: inventariare il codice personalizzato. Contate extension personalizzate, righe di Java, file Spring XML e dipendenze di terze parti.
# Contare file e righe Java
find . -name "*.java" -path "*/src/*" | wc -l
find . -name "*.java" -path "*/src/*" -exec cat {} \; | wc -l
# Contare configurazioni Spring XML
find . -name "*-spring.xml" -o -name "*-beans.xml" | wc -l
# Elencare i JAR di terze parti
find . -name "*.jar" -path "*/lib/*" | sort
Passo 2: creare un branch di migrazione. La migrazione tocca centinaia di file; tenetela separata dallo sviluppo di funzionalità.
git checkout -b migration/java21-spring6
Passo 3: aggiornare la build. Passate a Java 21 il JDK locale e la CI e impostate commerceSuiteVersion nel manifest.json su una versione 2211-jdk21 attuale.
Passo 4: migrazione del namespace con OpenRewrite. Applicate JavaxMigrationToJakarta e UpgradeToJava21 ed eseguite il commit.
Passo 5: eseguire le ricette Spring 6. Applicate le ricette per Spring Framework e Spring Security, rivedetele ed eseguite un commit separato.
Passo 6: correggere ciò che è sfuggito a OpenRewrite. Cercate i riferimenti javax. rimasti in XML, properties e letterali stringa.
# Trovare TUTTI i riferimenti javax rimanenti
grep -rn "javax\." --include="*.xml" --include="*.properties" \
--include="*.java" .
Passo 7: correggere gli errori di compilazione. Compilate e risolvete ogni errore; di solito modifiche alle API di Spring Security, comportamenti del JDK rimossi o librerie datate.
Passo 8: eseguire i test unitari e correggere i fallimenti. Riparate i test che falliscono per modifiche alle API; non cancellateli.
Passo 9: test di integrazione su un ambiente Java 21. Eseguite il deployment su un ambiente di staging Commerce Cloud con 2211-jdk21 e lanciate l’intera suite di integrazione e smoke test.
Passo 10: validare le prestazioni e andare in produzione. Eseguite i test di carico, confrontate con la baseline Java 17 e rilasciate.
Insidie frequenti
ClassNotFoundException a runtime. Tutto compila, ma un bean Spring fallisce all’avvio perché una configurazione XML fa ancora riferimento a javax.servlet.Filter come stringa. Controllate sempre i file XML.
Spring Security lascia passare tutto (o niente). Nel passaggio da WebSecurityConfigurerAdapter a SecurityFilterChain, un .build() mancante o un @Configuration dimenticato fanno ripiegare Spring su una configurazione predefinita. Testate esplicitamente autenticazione e autorizzazione.
Conflitti tra JAR di terze parti. Nella nostra esperienza è la trappola che costa più giorni. Una libreria include le proprie classi javax.* e dopo la migrazione nel classpath ci sono sia javax.servlet sia jakarta.servlet. Il risultato è una ClassCastException a runtime: un jakarta.servlet.http.HttpServletRequest non è un javax.servlet.http.HttpServletRequest, anche se i metodi sono identici. Rimuovete o aggiornate il JAR in questione.
Riferimenti a classi negli ImpEx. I file ImpEx possono fare riferimento a classi Java per translator e processori di import personalizzati. Se queste classi dipendono da tipi javax.*, l’import fallisce con un messaggio criptico. Controllate i vostri file ImpEx.
Versioni diverse nella pipeline di build. In locale gira Java 21, ma la pipeline CI o il manifest.json puntano ancora a una versione Java 17. In locale funziona tutto, il deployment fallisce. Aggiornate entrambi prima del primo tentativo di deployment.
La migrazione a Java 21 e Spring 6 è meccanica nella natura e ampia nella portata. OpenRewrite gestisce in modo affidabile il faticoso lavoro sul namespace. Resta il lavoro di ingegneria accurato: riscrivere Spring Security, configurazioni XML, reflection, librerie e test approfonditi. Se state pianificando anche cambiamenti più ampi della piattaforma, la nostra checklist di migrazione per SAP Commerce copre il resto del percorso.
Vi serve aiuto per stimare il perimetro nel vostro codice? Contattateci. Conosciamo questo update dal nostro lavoro su Commerce Cloud. Come lavoriamo con la piattaforma nel suo insieme lo mostra la nostra pagina SAP Commerce Cloud, e se state confrontando partner di implementazione vi aiuta la nostra panoramica dei migliori partner SAP Commerce Cloud in Svizzera.
Chiedete a Spadoom
Risposte basate su quanto Spadoom ha pubblicato su questo sito, con i link alle pagine di origine.
Provate una di queste
Risposte generate dall'IA. Verificate prima di agire. Le domande vengono salvate in forma anonima, senza indirizzo IP, per migliorare i nostri contenuti. Non inserite dati personali.
SAP Commerce Cloud partner di implementazione
Spadoom è il partner di implementazione SAP Commerce Cloud in Svizzera, Germania, Austria e Italia. Go-live mediano di 14 settimane. Clienti live in tutto il DACH.
Articoli correlati
SAP Hybris End of Life: la checklist completa per la migrazione 2026
La manutenzione mainstream di SAP Commerce on-premise (ex Hybris) è terminata il 31 luglio 2026. Cosa significa ora per voi, cosa passa da Hybris a Commerce Cloud e la checklist con cui migriamo: assessment, architettura, realizzazione, go-live e le settimane successive.
Da SAP Hybris a Commerce Cloud in 90 giorni: un playbook di migrazione
Come una piattaforma SAP Hybris di medie dimensioni arriva su SAP Commerce Cloud in 90 giorni: 30 giorni di preparazione, tre sprint, go-live. Il metodo dietro i nostri lanci commerce più rapidi, e cosa fare ora che la manutenzione mainstream dell'on-premise è terminata.
5 errori che le aziende commettono nella migrazione da SAP Commerce on-premise
I cinque errori che rendono lente e costose le migrazioni da SAP Commerce on-premise: copiare le personalizzazioni 1:1, sottovalutare i dati, trascinarsi il debito tecnico, il rilascio big bang e scambiare la manutenzione specifica per cliente per un piano. Con cosa fare invece.