Upgrading to Java 21 for AEM: What Developers Need to Know
Java 21 is now officially supported in Adobe Experience Manager as a Cloud Service (AEMaaCS), and for AEM developers, this upgrade is more than just a backend change — it’s a major opportunity to modernize how we write, manage, and scale code.
Announced in the January 2025 release of Cloud Manager (2025.1.0), Adobe confirmed Java 21 LTS will be enabled for all customers in February 2025. This means new builds will use Java 21 (if specified) alongside an upgraded SonarQube version, making it the perfect time to refactor and future-proof your AEM codebase.
In this article, we’ll cover:
✅ Why Upgrade?
Java 21 is the latest Long-Term Support (LTS) version, backed by Premier Support until 2028 and Extended Support until 2031. That’s the kind of stability AEM projects need. More importantly, Java 21 introduces cleaner syntax, better concurrency models, and powerful APIs that reduce boilerplate and improve performance.
For enterprise-grade AEM projects, that’s not just nice to have—it’s essential.
⚙️ How to Upgrade AEM Projects to Java 21
Upgrading your AEM project to Java 21 involves updating build configurations, dependencies, local development environments, and testing frameworks. Follow this step-by-step guide to ensure a smooth and effective migration:
1. Update Local Development Environment
Before making code changes, prepare your local machine to support Java 21:
This ensures your local build and testing will work with the new Java version as you progress.
2. Specify Java 21 for Cloud Manager Builds
Create a .cloudmanager folder in the root of your project, then add a file named java-version with the single content:
21
This instructs Adobe Cloud Manager to compile and run your builds using Java 21.
3. Update Maven Compiler Plugin
In your pom.xml, update the maven-compiler-plugin to target Java 21:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>21</source>
<target>21</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Recommended by LinkedIn
4. Enforce Java and Maven Versions with Maven Enforcer Plugin
Add or update the maven-enforcer-plugin in your pom.xml to require Maven 3.8.6+ and Java 21:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<id>enforce</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.8.6,)</version>
</requireMavenVersion>
<requireJavaVersion>
<message>Maven must be executed with a Java 21 JRE or higher.</message>
<version>21</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
5. Upgrade Maven Plugin Versions
Update your Maven plugins to versions compatible with Java 21 (recommended versions):
| Plugin | Version |
| ---------------------- | -------- |
| maven-release-plugin | 2.5.3 |
| maven-source-plugin | 3.0.1 |
| maven-assembly-plugin | 3.3.0 |
| maven-jar-plugin | 3.1.2 |
| maven-clean-plugin | 3.0.0 |
| maven-resources-plugin | 3.0.2 |
| maven-compiler-plugin | 3.8.1 |
| maven-install-plugin | 2.5.2 |
| maven-surefire-plugin | 2.22.1 |
| maven-failsafe-plugin | 2.22.1 |
| maven-deploy-plugin | 2.8.2 |
| maven-enforcer-plugin | 3.0.0-M3 |
6. Update Test Dependencies
Remove outdated testing dependencies like junit, mockito-inline, junit-jupiter (older versions), and junit-addons. Replace them with Java 21 compatible versions:
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.12.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.0-M3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.17.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.17.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.wcm</groupId>
<artifactId>io.wcm.testing.aem-mock.junit5</artifactId>
<version>5.6.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
7. Upgrade Required Packages
Make sure to upgrade these package versions in your dependencies:
bnd.version: 6.4.0
aemanalyser.version: 1.6.6
aem.sdk.api: [MATCH YOUR SDK VERSION]
org.objectweb.asm: 9.5+
org.apache.groovy: 4.0.22+
org.apache.aries.spifly.dynamic.bundle: 1.3.6+
8. Validate Your Build Locally
Run the following commands to verify that your build is compatible:
mvn --batch-mode org.apache.maven.plugins:maven-dependency-plugin:3.1.2:resolve-plugins
mvn --batch-mode org.apache.maven.plugins:maven-clean-plugin:3.1.0:clean -Dmaven.clean.failOnError=false
mvn --batch-mode org.jacoco:jacoco-maven-plugin:prepare-agent package
Be sure to run all unit and integration tests and fix any compatibility issues before pushing your changes.
This step-by-step upgrade guide will ensure your AEM project is fully prepared to leverage the performance, language improvements, and support benefits of Java 21.
Summary / Quick Developer Workflow
📌 Final Thoughts
Upgrading to Java 21 isn’t just about compliance—it’s about building faster, safer, and more expressive AEM code.
Take this as a moment to refactor legacy patterns, adopt new concurrency tools, and simplify your DTOs and service layers. The features introduced between Java 11 and 21 remove a lot of Java’s historical verbosity and open the door to writing cleaner, modern code across your AEM stack.
Now’s the time to upgrade. Happy coding!