23

We use maven and have artifacts that in turn depend on other internal artifacts. I am in the process of migrating to , and intend to migrate everything to Java 9 first without modularizing the code (i.e. in the unnamed module).

The problem I run into is that we depend on java.xml.bind, which is now not included in the default modules. Is there a "correct" way to express this dependency on java.xml.bind with Maven?

Naman
  • 27,789
  • 26
  • 218
  • 353
Kevin Peterson
  • 7,189
  • 5
  • 36
  • 43

4 Answers4

22

The Module System speaks of the way the unnamed modules as in your case of loading the application from classpath constructs the module graph. Further, from the documentation itself:-

When the compiler compiles code in the unnamed module, or the java launcher is invoked and the main class of the application is loaded from the class path into the unnamed module of the application class loader, then the default set of root modules for the unnamed module is computed as follows:

  • The java.se module is a root, if it exists. If it does not exist then every java.* module on the upgrade module path or among the system modules that exports at least one package, without qualification, is a root.

  • Every non-java.* module on the upgrade module path or among the system modules that exports at least one package, without qualification, is also a root.

Otherwise, the default set of root modules depends upon the phase:

  • At compile time it is usually the set of modules being compiled (more on this below);

  • At link time it is empty; and

  • At run time it is the application's main module, as specified via the --module (or -m for short) launcher option.

It is occasionally necessary to add modules to the default root set in order to ensure that specific platform, library, or service-provider modules will be present in the module graph. In any phase the option

--add-modules <module>(,<module>)* where <module> is a module name, adds the named modules to the default set of root modules.

Similar issue was faced in jetty.project where a thread from jdk mailing list discussed over the same and the fix was to use:

--add-modules java.se.ee

which provided them access to all Java SE modules and in your case shall simply be:

--add-modules java.xml.bind

To use this in maven, you can embed the same to the maven-compiler-plugin using

<compilerArgs>
    <arg>--add-modules</arg>
    <arg>java.xml.bind</arg>
</compilerArgs>

as suggested by ZhekaKozlov here.


An important point to note is that marking deprecation of an API also means you might probably want to get away from using it. To adapt to this way you can probably start consuming the dependency on jaxb-api:2.3.0 which can now be loaded as a module and can be executed from the classpath as well. The change you need to make is to add the following to your dependencies list:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>

Update:- Eventually, with Java-10 already out and JDK/11 up next, one should ideally follow the link to JEP 320: Remove the Java EE and CORBA Modules and further replace such dependencies with their standalone libraries instead.

Naman
  • 27,789
  • 26
  • 218
  • 353
  • Doesn't work for me, it still gives me `java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory` – Andremoniy Jan 07 '18 at 10:18
  • @Andremoniy The answer was to suggest to make use of the Java EE features from the following in preference order - 1. standalone libraries 2. built-in modules (using `--add-modules`). The exception you've faced seems to be over the `com.sun.*` package which [has been removed in JDK9.](https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-F7696E02-A1FB-4D5A-B1F2-89E7007D4096) On another note, maybe explaining the issue faced by you in another thread would make is a little clearer and easy to debug. – Naman Jan 07 '18 at 10:28
  • nope. I've tried to create a simplest project with just line of `main` method: `JAXBContext jaxbContext = JAXBContext.newInstance( Foo.class );`. I've have added dependency on jaxb-api and added `add-module` argument. – Andremoniy Jan 07 '18 at 10:34
  • Looks like no one of this solutions works properly (might be it was changed something in the recent JDK). Please, see my this answer: https://stackoverflow.com/a/48136912/1479414 . - that's only one solution which works fine for me. – Andremoniy Jan 07 '18 at 12:14
  • @Andremoniy You probably misunderstood the answer here. The one with ---add-modules is for the ee module inbuilt with jdk to be used. Other one with jaxb dependency doesn't need the argument since that would itself bring in an automatic module in the modulepath and the inbuilt one would not be used. (previously I drew a line separator to distinguish these two ways in the answer) – Naman Jan 07 '18 at 12:20
  • You are right: I did misunderstand that. But in fact both distinct solutions do not work. – Andremoniy Jan 07 '18 at 12:21
  • I mean, that I have tried both of them independently, and no one works fine. Please try it by your self. I would be glad if you could point on my mistake. – Andremoniy Jan 07 '18 at 12:22
  • In the upshot I came to the solution provided by my answer I linked above – Andremoniy Jan 07 '18 at 12:22
  • @Andremoniy Did you check [this answer](https://stackoverflow.com/questions/46220810/add-modules-only-on-compilation/46221811#46221811)? I am not able to draw the difference in yours from this. Is it that you are saying that all the dependencies in your answer are a must? – Naman Jan 08 '18 at 08:59
  • yes I do. And I confirm that it doesn't work with just `jaxb-api` dependency (it will compile fine with it, but will throw ClassNotFoundException's in the runtime). And yes, all of libraries I have provided seem to be mandatory for consistent work. – Andremoniy Jan 08 '18 at 09:07
11

Yes, you have to pass --add-modules to Java compiler:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.7.0</version>
    <configuration>
        <release>9</release>
        <compilerArgs>
            <arg>--add-modules</arg>
            <arg>javax.xml.bind</arg>
        </compilerArgs>
    </configuration>
</plugin>

Then your project should compile fine.

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • 2
    Should use `3.6.2` though, https://cwiki.apache.org/confluence/display/MAVEN/Java+9+-+Jigsaw – Naman Sep 07 '17 at 03:05
  • It would work for some. But eventually, when you want this to be useful for future readers, you must ensure it's updated with the ongoing changes. Just a suggestion. ;) – Naman Sep 07 '17 at 03:47
  • @nullpointer I used this article as a source: https://github.com/CodeFX-org/mvn-java-9 – ZhekaKozlov Sep 07 '17 at 03:49
  • 2
    And I am sure we can suggest the author to update in that case(@Nicolai might just read this as well ). I would consider the link shared by me would be official instead. – Naman Sep 07 '17 at 03:51
9

JAXB, along with the other APIs shared with Java EE (JAX-WS, JAF, JTA, and the so-called "Common Annotations") are deprecated in Java SE 9 and are proposed to be removed in a future release of Java SE and the JDK. Each of these APIs has a standalone version/download. Each API has its own JSR that maintains it too. Transitioning from the APIs included in the JDK to the standalone versions will of course be a bit disruptive.

A first step towards dropping these APIs from Java SE and the JDK is to not resolve the modules containing these APIs by default. When you compile or run code on the class path with JDK 9 then it will initially appear that the APIs do not exist. A quick workaround, as noted in another answer, is to compile or run with --add-modules java.xml.bind. That CLI option adds the "java.xml.bind" module to the set of root modules to resolve at startup and it works with JDK 9 because this module is included in the JDK run-time image.

Beyond the quick workaround, applications or libraries using JAXB will need to move to using the standalone version of the API/implementation. JAXB 2.3.0 is due to be published to Maven Central soon and it includes the changes to work with JDK 9 and beyond. The standalone version can be deployed on the class path like other JAR files. It will eventually be possible to deploy the standalone version on the (upgrade) module path and use it as a module too. The JDK 9 Migration Guide will have more information on the options for migrating code that uses JAXB or the other APIs shared with Java EE.

Alan Bateman
  • 5,283
  • 1
  • 20
  • 25
2

Okay I hope this helps someone. If you, per chance, have installed Java 9 or 10 and find that you can't get past this javax.xml.bind error, perhaps you are using Java 8 by way of jenv per folder (really I am sorry to be so vague, but, that's all I have time for at the moment)?

But adding in a correct setting for JAVA_HOME fixed my problem: export JAVA_HOME="$(/usr/libexec/java_home -v 1.8)" on MacOS.