Vai al contenuto
Migrazione SAP Commerce Cloud a Java 21 + Spring 6: guida per sviluppatori
Implementation · Pubblicato per la prima volta il ·Aggiornato il da Cyrill Pedol ·12 min di lettura

Migrazione SAP Commerce Cloud a Java 21 + Spring 6: guida per sviluppatori

Cyrill Pedol

Cyrill Pedol

SAP Commerce Lead, Spadoom AG

Condividi

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.* a jakarta.*, riscrivere le configurazioni Spring Security con SecurityFilterChain, 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 bean SecurityFilterChain
  • authorizeRequests() diventa authorizeHttpRequests()
  • antMatchers() diventa requestMatchers()
  • csrf(), cors() e sessionManagement() si configurano tramite la DSL lambda
  • Il SecurityContext non 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 da StandardServletMultipartResolver. 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/products sono 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 di AntPathMatcher su 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 UserType vanno aggiornate; l’interfaccia ha cambiato firma generica.
  • Annotazione @Type modificata. @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 lanciano UnsupportedOperationException. 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.reflect e altri) falliscono se non sono impostati flag --add-opens espliciti. Meglio aggiornare la libreria che aggiungere flag.
  • Finalization: destinata alla rimozione. Sostituite finalize() con Cleaner o 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.* a jakarta.*
  • Rimozione dell’adapter di Spring Security e passaggio alla DSL lambda
  • Ridenominazione di antMatchers() in requestMatchers()
  • 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.xml e *-beans.xml che fanno riferimento a classi javax.*
  • 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:

  1. Tempo di avvio: confrontate gli avvii a freddo tra build Java 17 e Java 21
  2. Uso della memoria: osservate l’uso dell’heap sotto carico
  3. Throughput: eseguite i test di carico standard e confrontate i tempi di risposta
  4. 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.

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

Chiedete a Spadoom

Risposte basate su quanto Spadoom ha pubblicato su questo sito, con i link alle pagine di origine.

Provate una di queste

Invio per inviare · Maiusc+Invio per andare a capo 0 / 600
Proseguire con un esperto Apre il modulo di contatto con la vostra domanda.

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.

Prossimo passo

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