Seamless Java JDK 21 Upgrade: Solving Dependency and Build Challenges
This article outlines the motivations, progress, and common issues encountered when upgrading over 100 Java applications to JDK 21, including deprecated APIs, module system constraints, Maven plugin incompatibilities, and GC choices, and provides concrete migration steps, configuration templates, and best‑practice recommendations for a smooth transition.
Background and Challenges
Upgrade Drivers
Oracle long‑term support strategy
Modern feature requirements: coroutines, pattern matching, ZGC, etc.
Security and performance needs
Version requirements introduced by new AI technologies
Project Situation
Coordinated upgrade of over 100 projects
Multiple technology stacks coexist
Adaptation challenges for the continuous‑integration system
Progress
Total Applications
Completed
Decommissioned
Pending Upgrade
100+
73
13
10+
Main Problem Domains and Solutions
1. Dependency "Butterfly Effect"
Internal APIs such as
sun.misc.BASE64Encoderremoved → compilation errors
JAXB/JAX‑WS stripped from JDK core → XML processing chain broken
Lombok compatibility issues with new compiler (especially
recordtypes)
Root cause: JEP 320 (Encapsulate JDK Internals) – https://openjdk.org/jeps/320
Case 1: Legacy SDK compilation trap
<code>Compilation failure: Compilation failure:
#14 4.173 [ERROR] Source option 6 is no longer supported. Use 8 or higher.
#14 4.173 [ERROR] Target option 6 is no longer supported. Use 8 or higher.</code>Old Maven compiler plugin configuration:
<code><plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</code>Updated configuration using
releaseparameter:
<code><plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>8<!-- unified release parameter -->
</configuration>
</plugin>
</code>Case 2: JAXB modular removal
<code>javax.xml.bind.JAXBException: Implementation of JAXB‑API has not been found</code> <code><dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
</dependency>
</code>Case 3: Lombok compatibility with new compiler
<code>java.lang.NoSuchFieldError</code> <code><dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
</code>Case 4: Missing @Resource annotation
<code>Caused by: java.lang.NoSuchMethodError: 'java.lang.String javax.annotation.Resource.lookup()'</code> <code><dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>1.3.5</version>
</dependency>
</code>Recommendation: Use the Jakarta standard and exclude the old
jsr250-apidependency.
2. Modular "Wall" and Reflection Access
Example error:
<code>[ERROR] Unable to make field private int java.text.SimpleDateFormat.serialVersionOnStream accessible</code>Solution: Add module‑open JVM arguments, e.g.:
<code>--add-opens java.base/java.text=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
</code>Full template for module opening:
<code>export JAVA_OPTS="-Djava.library.path=/usr/local/lib -server -Xmx4096m \
--add-opens java.base/sun.security.action=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.math=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/sun.util.calendar=ALL-UNNAMED \
--add-opens java.base/java.util.concurrent=ALL-UNNAMED \
--add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED \
--add-opens java.base/java.security=ALL-UNNAMED \
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED \
--add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED \
--add-opens java.base/java.net=ALL-UNNAMED \
--add-opens java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens java.management/java.lang.management=ALL-UNNAMED \
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED \
--add-opens java.management/sun.management=ALL-UNNAMED \
--add-opens java.base/sun.security.action=ALL-UNNAMED \
--add-opens java.base/sun.net.util=ALL-UNNAMED \
--add-opens java.base/java.time=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens java.base/java.io=ALL-UNNAMED"
</code>3. Syntax‑Level "Time‑Travel"
Case 1: Base64 encoding rewrite
<code>// JDK 8 style (deprecated)
BASE64Encoder encoder = new BASE64Encoder();
String encoded = encoder.encode(data);
// JDK 21 style
Base64.Encoder encoder = Base64.getEncoder();
String encoded = encoder.encodeToString(data);
</code>Case 2: Date serialization issue
<code>Caused by: java.lang.reflect.InaccessibleObjectException:
Unable to make field private int java.text.SimpleDateFormat.serialVersionOnStream accessible
</code>Solution: Use
DateTimeFormatterinstead of
SimpleDateFormat, or add the appropriate
--add-opensflag.
Best‑Practice Summary
1. Local Compilation
Compile locally first to catch syntax errors, version conflicts, and incompatibilities. Typical scenarios include Base64 migration, Lombok version upgrade, annotation package conflicts, and Maven plugin upgrades.
2. Cloud Build
Align with local compilation results; ensure proper JDK 21 image and module opening configuration.
3. Cloud Deployment
Address image mismatches, module permissions, and JDSecurity encryption handling. Use the provided module‑opening template.
4. JVM Tuning
Choose appropriate garbage collector based on workload:
UseParallelGC – high throughput, longer pauses, suitable for batch processing.
UseG1GC – balanced throughput and latency, suitable for moderate‑size heaps.
UseZGC – ultra‑low latency, suitable for very large heaps (TB scale).
Adjust GC choice according to application requirements.
JD Cloud Developers
JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.