JAXB on Java 9, 10, 11 and beyond
If you have programs that use JAXB (Java Architecture for XML Binding) and you’ve tried to compile and run them on Java versions newer than Java 8, you’ll have noticed that you get errors. There are changes in Java SE 9, 10 and 11 that you need to know about to understand and solve these errors. In this post we will take a look at what has changed and what you need to do to use JAXB on Java 9 and beyond.
Let’s first take a look at the errors that you’ll get when you try to run or compile a program that uses JAXB on the newer Java versions.
Running a JAXB program on Java SE 9 or newer
When you run a program that was compiled with JDK 8 or older on Java SE 9 or newer, you’ll get a NoClassDefFoundError that tells you that classes in the package javax.xml.bind cannot be found, for example:
Error: Unable to initialize main class com.jesperdj.jaxb.Example Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
Compiling a JAXB program on JDK 9 or 10
When you compile a program that uses JAXB using JDK 9 or 10, you’ll get errors indicating that the package javax.xml.bind is not visible:
src/main/java/com/jesperdj/jaxb/Example.java:9: error: package javax.xml.bind is not visible import javax.xml.bind.JAXBContext; ^ (package javax.xml.bind is declared in module java.xml.bind, which is not in the module graph)
Compiling a JAXB program on JDK 11 or newer
When you compile a program that uses JAXB on JDK 11 or newer, you’ll get errors indicating that the package javax.xml.bind and the classes in it do not exist at all:
src/main/java/com/jesperdj/jaxb/Example.java:9: error: package javax.xml.bind does not exist import javax.xml.bind.JAXBContext; ^ src/main/java/com/jesperdj/jaxb/Example.java:23: error: cannot find symbol JAXBContext context = JAXBContext.newInstance(PurchaseOrder.class); ^ symbol: class JAXBContext location: class Example
Using the xjb and schemagen tools on JDK 11
The JAXB-specific xjc and schemagen tools, which you use to convert an XML Schema (*.xsd file) to a set of Java classes and vice versa, are included with the JDK up to version 10, but have been removed in JDK 11.
When you try to use these tools with JDK 11 or newer, you’ll get a “command not found” or similar error.
Java’s standard library isn’t exactly small and lightweight. In the course of the past 20+ years, many features have been added to it, mostly because at the time it was thought that it would be a good idea if Java supported a particular technology out-of-the-box.
One of these was support for XML-based web services. When Java SE 6 was released in December 2006, XML-based web services were popular, so the developers of the Java language thought it would be a good idea if Java would have support for calling web services as a standard feature. It was decided to add the necessary APIs, that were originally developed as part of Java EE, to Java SE. Among these were JAX-WS (Java API for XML-Based Web Services) and JAXB.
With today’s trend towards microservices, it’s important that the Java runtime environment is small and lightweight, so having a large runtime library with built-in support for every possible technology isn’t as advantageous anymore.
Therefore, a proposal was made in JEP-320 to remove the Java EE and CORBA modules from the JDK.
This means the following:
- In Java SE 9 and 10, the module java.se.ee, which contains JAX-WS, JAXB and a few other Java EE APIs, is still included but is deprecated, and not included in the module path by default. You need to explicitly enable it if you want to use it.
- In Java SE 11, the module java.se.ee has been removed. To use JAX-WS and JAXB you need to add them to your project as separate libraries.
Of course, you want to know what exactly you need to do to use JAXB in Java SE 9 and newer. Read on to find out how to make it work.
Not recommended: Enabling the deprecated module
One way to make your JAXB program compile on JDK 9 or 10 is to explicitly enable the deprecated module java.se.ee on the command line using the –add-modules option, for example:
$ javac -s src/main/java -d target/classes --add-modules java.se.ee `find src/main/java -name '*.java'`
You can do the same thing when you run the program, for example:
$ java -cp target/classes --add-modules java.se.ee com.jesperdj.jaxb.Example
This solution is not recommended however, because it will not work on JDK 11 or newer, where the module java.se.ee has been removed completely.
A better solution is to not use the java.se.ee module at all, and add JAXB to your project as a separate library, as described below.
Adding JAXB as a separate library
The proper solution is to add the JAXB as a dependency to your project – in the same was as you would have done long ago, before Java 6.
The official JAXB API dependency can be found in the Maven Central repository, so if you’re using Maven, you’ll want to add the following dependency to your project:
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency>
Like many Java EE APIs, JAXB is just an API – a specification of a number of classes and interfaces. To use JAXB you not only need to have a dependency on the API, you also need to make sure that an implementation of the API is available in the runtime environment of your program.
When your program is running in a Java EE container, there might already be an implementation of JAXB available so you won’t need to add it. When you run your program on a plain Java runtime environment, you’ll need to include an implementation yourself.
You have several options at this point. You can use the reference implementation of JAXB, which was what was formerly included in the JDK, or you can use an alternative implementation such as EclipseLink MOXy.
Using the reference implementation
There are Maven artifacts available for the official JAXB reference implementation.
The JAXB Users Guide refers to the following artifact:
<dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.1</version> <scope>runtime</scope> </dependency>
Using EclipseLink MOXy
EclipseLink MOXy is an alternative implementation of the JAXB API that you might want to use. To use this, include the following dependency in your project next to the dependency on javax.xml.bind:jaxb-api:
<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.moxy</artifactId> <version>2.7.3</version> <scope>runtime</scope> </dependency>
Note that in order to use EclipseLink MOXy, you’ll need to add a jaxb.properties file to your project to specify that you want to use a different JAXB context factory. See Specifying the EclipseLink MOXy Runtime in the documentation for more details.
Using the JAXB tools on JDK 11 or newer
Since JAXB has been completely removed from Java SE 11, the xjc and schemagen tools are also no longer available.
If you want to use these tools from the command line, you can download and install the JAXB reference implementation standalone distribution, or download and install GlassFish, which also includes them.
However, unfortunately both of these plugins seem to currently have issues when you use them on JDK 9 or newer – maybe the real issue is not in the plugins but in the xjc tool itself. This means that for the moment, you’ll have to find a workaround for these issues, or wait until they have been resolved.
If you need to use JAXB on Java SE 9 or newer you need to be aware that there are breaking changes, and you’ll need to update your project to make it work.
I have a course available on Pluralsight about JAXB: Working with XML in Java using JAXB. Take a look at it if you want to learn how to use JAXB!