I just announced the new Spring Boot 2 material, coming in REST With Spring:
For anyone who has tried upgrading to Java 9, they have likely experienced some sort of NoClassDefFoundError when compiling code that previously worked in earlier versions of Java.
In this article, we’ll look at a common missing class, JAXBException, and different ways we can solve it. The solutions provided here are generally applicable to any class that may be missing when upgrading to Java 9.
2. Why Java 9 Cannot Find JAXBException?
One of the most discussed features of Java 9 is the module system. The goal of the Java 9 module system is to break apart the core JVM classes and related projects into stand-alone modules. This helps us create applications with smaller footprints by only including the minimum required classes to run.
The downside is that many classes are no longer available on the classpath by default. In this case, the class JAXBExceptioncan be found in one of the new Java EE modules named java.xml.bind. As this module isn’t required by the core Java runtime, it’s not available on the classpath by default.
Trying to run an application that uses JAXBExceptionwill result in:
To get around this we must include the java.xml.bindmodule. As we’ll see below, there are multiple ways to accomplish this.
3. Short-Term Solution
The quickest way to make sure the JAXB API classes are available to an application is to add use the –add-modules command line argument:
However, this might not be a good solution for a couple of reasons.
First, the –add-modules argument is also new in Java 9. For applications that need to run on multiple versions of Java, this presents some challenges. We’d have to maintain multiple sets of build files, one for each Java version the application runs on.
To work around this we could also use the -XX:+IgnoreUnrecognizedVMOptionscommand line argument for older Java compilers.
However, this means any typo or misspelled argument won’t be brought to our attention. For example, if we try to set a minimum or maximum heap size and mistype the argument name, we won’t get a warning. Our application will still start, but it will be running with a different configuration than we expect.
Second, the –add-modules option will be deprecated in a future Java release. This means at some point after we upgrade to a new version of Java, we’ll face the same problem of using an unknown command line argument and have to address the issue again.
4. Long-Term Solution
There is a better approach that will work across different versions of Java and will not break with future releases.
The solution is to utilize a dependency management tool such as Maven. With this approach we would add the JAXB API library as a dependency just like any other library:
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency>
The above library only contains the JAXB API classes, which includes JAXBException. Depending on the application we may need to include other modules.
Also keep in mind that the Maven artifact names may be different than the Java 9 module name, as is the case for JAXB API. It can be found on Maven Central.
The Java 9 module system provides a number of benefits such as decreasing application size and better performance.
However, it also introduces some unintended consequences. When upgrading to Java 9 it is important to understand which modules an application truly requires and take steps to ensure they are available on the classpath.