Why Upgrade to JDK 11? A Practical Guide to Migrating Java 8 Projects and Tomcat 8.5
This article explains the motivations for moving a Java 8 project to JDK 11, compares JDK 11 and JDK 17, outlines JDK 11’s key features, details Tomcat 8.5 differences, provides step‑by‑step migration instructions, and shares troubleshooting tips for common upgrade issues.
Background
Project upgrade to JDK 11 is driven by several reasons: JDK 8 stopped receiving updates in Jan 2019; many frameworks and third‑party libraries require JDK 11 or higher (Spring 5.3+, Hibernate 5.4+, Tomcat 10, Jetty 10, Apache POI 5.0+, Lucene 8.7+, JUnit 5.7+); and JDK 21 will bring many performance and security improvements.
Therefore upgrading is necessary even if only for security patches and performance gains.
Version selection
JDK releases follow a six‑month cadence, with an LTS version roughly every three years. Current LTS versions are JDK 8, JDK 11, JDK 17, and JDK 21. For this upgrade JDK 11 and JDK 17 are considered; JDK 11 is chosen because it is widely adopted, has richer migration guides, and allows a staged upgrade from JDK 8 → JDK 11 → JDK 17.
Consequently Tomcat 7 is also upgraded to Tomcat 8.5.
JDK 11 Features
Key JDK 11 features relevant to the project include:
ZGC – an experimental scalable low‑latency garbage collector (Linux/x64 only) with pause times under 10 ms, capable of handling heaps from hundreds of MB to several TB, and with ≤ 15 % throughput impact compared to G1.
Standardized HTTP Client API (JEP 323) supporting asynchronous, non‑blocking calls, HTTP/2, and full compatibility with popular libraries.
Docker container improvements – from JDK 10 onward the JVM respects cgroup memory and CPU limits and provides options to fine‑tune heap usage.
JDK 11 also removed several Java EE and CORBA modules (e.g., JAX‑WS, JAXB, JAF, CORBA, JTA). Projects that depend on these modules must add explicit Maven dependencies, as shown in the table below.
Removed module
Affected package
Maven dependency
Java API for XML Web Services (JAX‑WS)
java.xml.ws
https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt
Java Architecture for XML Binding (JAXB)
java.xml.bind
https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime
JavaBeans Activation Framework (JAF)
java.activation
https://mvnrepository.com/artifact/javax.activation/activation
Common Annotations
java.xml.ws.annotation
https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
Common Object Request Broker Architecture (CORBA)
java.corba
https://mvnrepository.com/artifact/org.glassfish.corba/glassfish-corba-orb
Java Transaction API (JTA)
java.transaction
https://mvnrepository.com/artifact/javax.transaction/jta
Tomcat version differences
Tomcat 7 (Servlet 3.0) and Tomcat 8.5 (Servlet 3.1) differ in servlet spec support, WebSocket capabilities, JSP spec, remote configuration API, and multithreading performance. The order in which JAR files are loaded also changed: Tomcat 7 sorts JARs alphabetically, while Tomcat 8.5 loads them in the order returned by the file system, which can cause nondeterministic behavior across operating systems.
Class‑loader hierarchy for Tomcat includes Bootstrap, Extension, Application, Common, Catalina, Shared, and WebApp class loaders. The loading order can affect which version of a class is chosen, leading to runtime errors.
Tomcat 7 loads JARs from
WEB-INF/libalphabetically (see diagram below):
Tomcat 8.5 loads JARs directly without sorting, which can lead to different loading orders on Windows vs. Linux:
To enforce a specific loading order, the required JAR can be placed in
PreResourcesvia
META-INF/context.xml:
<code><?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resources>
<PreResources base="${catalina.base}/webapps/${project}/WEB-INF/lib/a-suishen-patch-libs-1.0-SNAPSHOT.jar"
className="org.apache.catalina.webresources.JarResourceSet"
webAppMount="/WEB-INF/classes"/>
</Resources>
</Context></code>Upgrade steps
Code modifications – follow Microsoft’s migration guide from Java 8 to Java 11 and adjust third‑party dependencies (e.g., javassist 3.23.1‑GA, ASM 7.0, Byte Buddy 1.9.0, cglib 3.2.8, Mockito 2.20.0).
Set JVM parameters, e.g.:
<code>-Xms3000m -Xmx3000m -XX:+UseCompressedOops -XX:+PrintGCDetails -Xloggc:./logs/gc.log -XX:+TieredCompilation -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:MaxTenuringThreshold=15 -XX:+AlwaysPreTouch</code>Deploy the project and monitor catalina, localhost, and application logs for errors.
Upgrade issue summary
Common problems encountered and their solutions include:
NoClassDefFoundError: javafx/util/Pair – caused by removal of JavaFX in JDK 11; fix by adding JavaFX dependencies.
NoClassDefFoundError: javax/xml/bind/JAXBException – caused by removal of JAXB; fix by adding JAXB dependencies.
Jar conflict NoSuchMethodError – duplicate
BeanUtilsBeanclasses; resolve by excluding the conflicting JAR after inspecting the dependency tree.
javassist version mismatch – JDK 11 incompatibility with older javassist; upgrade to 3.23.1‑GA.
log4j delegation loop – caused by mixing
log4j‑over‑slf4jand
slf4j‑log4j12(or JCL equivalents); exclude one of the conflicting jars.
CORS configuration error – newer Tomcat rejects
allowedOrigins=[*]when
supportsCredentials=true; set
supportsCredentials=falseor use
allowedOriginPatterns.
Outlook
After migrating to JDK 11 and Tomcat 8.5, the team plans to leverage the new ecosystem for startup optimization and development convenience, aiming for further performance gains.
WeiLi Technology Team
Practicing data-driven principles and believing technology can change the world.
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.