In Java 11, the JAXB module is removed, and the “open modules” example from Core Java for the Impatient no longer works. I had to find a module in the wild to replace it. How is the grand social experiment of library modularization coming along? Not too badly, actually.
I am updating the chapter on the Java Platform Module System for the 11th edition of Core Java. Recall that a module must open a package to another module that wants runtime access to its private fields. Suppose, for example, you have a package
com.myapp.models and you want to use JPA to persist objects, or JAXB to turn them into XML. (These libraries use reflection to peek inside the private fields.) And suppose JPA or JAXB is also in a module. Then you need to add a declaration
opens com.myapp.models to java.xml.bind;
module-info.java file of your
In Core Java for the Impatient, I used JAXB because it was in a module—right in the Java 9 platform. Unfortunately, that module is being removed in Java 11, together with a few other modules that rightly belong into Java EE, erm, Jakarta EE.
So, I have to find another library module that uses reflective access. What about JAXB? Surely there is a replacement module available, right? The JAXB web site offers a download, and
jaxb-api.jar has a
module-info.class. There is a dependency to the
java.activation module. According to https://github.com/javaee/activation, the latest version is 1.2.0. Maven Central has the JAR. And it has an
MANIFEST.MF. On the module path it goes. The program compiles.
To run, I need
jaxb-core.jar. On the module path they go. And disaster strikes:
Error occurred during initialization of boot layer java.lang.module.ResolutionException: Module jaxb.core contains package com.sun.xml.bind.marshaller, module jaxb.impl exports package com.sun.xml.bind.marshaller to jaxb.core
com.sun.xml.bind.marshaller is split among the two JARs. So that's a dead end for now.
How about a similar project that has a single modular JAR and no dependencies, like, Gson. The Maven Central JAR is not modular, but the Github repo has a
module-info.java—strangely, inside a
src/main/java/com.google.gson directory. Moving it to the right place and a couple of adjustments in the
build.gradle file did the trick. The test program compiled. Does it run? Not with JDK 11. It can't parse the version number
It works with JDK 10. Great. But wait—I forgot to open my package for runtime access. It shouldn't have worked.
Looking at the implementation, I saw that Gson uses reflection for versions < 9. Starting with JDK 9, they use . . .
sun.misc.Unsafe. Java 9 has driven them away from safety!
After patching up the version-processing code, I can run with JDK 11, and the call
unsafeClass = Class.forName("sun.misc.Unsafe");
fails in the
com.google.gson module. That's good. By falling back on reflection, I have the desired behavior—clients need to open their packages to the module.
Not knowing if the Gson folks will do the right thing by the time the book comes out, I kept looking. On to JSON-B. I built the Yasson reference implementation from source. I also needed to build the API JAR. They both came with
module-info.java files. My sample program compiled.
Did it run? No.
For some reason, the serialization accesses
java.sql.Date, and the
org.eclipse.yasson didn't require the
java.sql module. I filed a bug report, and it was fixed the next day.
That's the example that will make it into the book. They are close enough that I have hope that they will publish a modular JAR on Maven Central in time.
In Core Java for the Impatient, I wrote: “The migration plan to modules is a great social experiment, and nobody knows whether it will end well.”
It doesn't seem to be going too badly. Projects are grappling with
module-info.java. There are some missteps along the way, but they will surely get sorted out with time.
Comments powered by Talkyard.