Jooq: Code generator doesn't run on Java 9 early access

Created on 1 Aug 2017  路  13Comments  路  Source: jOOQ/jOOQ

Given this project:

https://github.com/michael-simons/bootiful-databases

Using JDK 9-EA

java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+180)
Java HotSpot(TM) 64-Bit Server VM (build 9+180, mixed mode)

And jOOQ 3.9.4 with the corresponding code generator

Start a postgres database from within the project

./mvnw docker:start

Try to generate jOOQ-Metamodel:

./mvnw clean compile

After having the migrations applied, jOOQs code generator runs and fails as follows:

[ERROR] Failed to execute goal org.jooq:jooq-codegen-maven:3.9.4:generate (default) on project bootiful-databases: Execution default of goal org.jooq:jooq-codegen-maven:3.9.4:generate failed: A required class was missing while executing org.jooq:jooq-codegen-maven:3.9.4:generate: javax/xml/bind/JAXB
[ERROR] -----------------------------------------------------
[ERROR] realm =    plugin>org.jooq:jooq-codegen-maven:3.9.4
[ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
[ERROR] urls[0] = file:/Users/msimons/.m2/repository/org/jooq/jooq-codegen-maven/3.9.4/jooq-codegen-maven-3.9.4.jar
[ERROR] urls[1] = file:/Users/msimons/.m2/repository/org/jooq/jooq-codegen/3.9.4/jooq-codegen-3.9.4.jar
[ERROR] urls[2] = file:/Users/msimons/.m2/repository/org/jooq/jooq/3.9.4/jooq-3.9.4.jar
[ERROR] urls[3] = file:/Users/msimons/.m2/repository/org/jooq/jooq-meta/3.9.4/jooq-meta-3.9.4.jar
[ERROR] urls[4] = file:/Users/msimons/.m2/repository/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar
[ERROR] urls[5] = file:/Users/msimons/.m2/repository/org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar
[ERROR] urls[6] = file:/Users/msimons/.m2/repository/org/codehaus/plexus/plexus-utils/1.5.15/plexus-utils-1.5.15.jar
[ERROR] urls[7] = file:/Users/msimons/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar
[ERROR] Number of foreign imports: 1
[ERROR] import: Entry[import  from realm ClassRealm[maven.api, parent: null]]
[ERROR] 
[ERROR] -----------------------------------------------------
[ERROR] : javax.xml.bind.JAXB

Same error occurs on https://github.com/springbootbuch/database_examples and I assume on plain (without the Spring Boot stuff) jOOQ projects as well.

Build High Answered Support request

Most helpful comment

Workaround

This particular issue can be worked around by specifying (example using Windows shell syntax):

set MAVEN_OPTS=%MAVEN_OPTS% --add-modules java.xml.bind

An (outdated) explanation can be seen here:
http://mail.openjdk.java.net/pipermail/jdk9-dev/2016-May/004309.html

Possible fix

Will continue investigating. There are several possible options for a fix:

1) There might be a clean fix where jOOQ imports all the required JDK modules, e.g. by specifying this in a module-info.java. We'd have to see if this can be done also in the JDK 8 build, or if we need a separate JDK 9 build for this.
2) We could intercept the NoClassDefFoundError and print a message with the above workaround
3) Other possible solution...

All 13 comments

Thanks for your report. I can reproduce this. Will investigate ASAP

Workaround

This particular issue can be worked around by specifying (example using Windows shell syntax):

set MAVEN_OPTS=%MAVEN_OPTS% --add-modules java.xml.bind

An (outdated) explanation can be seen here:
http://mail.openjdk.java.net/pipermail/jdk9-dev/2016-May/004309.html

Possible fix

Will continue investigating. There are several possible options for a fix:

1) There might be a clean fix where jOOQ imports all the required JDK modules, e.g. by specifying this in a module-info.java. We'd have to see if this can be done also in the JDK 8 build, or if we need a separate JDK 9 build for this.
2) We could intercept the NoClassDefFoundError and print a message with the above workaround
3) Other possible solution...

A similar issue has been encountered when building jetty with JDK 9:
https://github.com/eclipse/jetty.project/issues/1265

The solution there was to include

--add-modules java.se.ee

A word of warning about --add-modules java.se.ee. It can be a bag of hurt if you're using JTA as some, but not all, JTA classes are in that module. That split leads to failures at runtime.

FWIW, we have this general problem in Spring Boot too. We intend to address it by adding Maven dependencies for various things (JAXB, JSR-330, etc) instead of relying on them coming from the JDK.

The blanket --add-modules java.se.ee is not the best thing to do. Better to only add the specific modules you need. All of those are endorsed standards or standalone technologies, so looking for libs that implement them and explicitly depending on them is a good solution, too.

Thanks for the hint, @wilkinsona. jOOQ doesn't have a JTA dependency.

Closing this now, as the workaround is the only reasonable solution prior to creating an actual JDK 9 build (#6486).

Thanks for clarifying the issue.

For future reference: There's another fix, which does not use MAVEN_OPTS and can be maintained local to the project. See this answer on StackOverflow.

This particular issue could also be solved without modularising the library, by specifying an explicit Maven dependency on the JAXB API (see #6610), as @wilkinsona also mentioned in his comment: https://github.com/jOOQ/jOOQ/issues/6477#issuecomment-319496039.

However, this will lead to a new error:

[ERROR] Failed to execute goal org.jooq:jooq-codegen-maven:3.10.0-SNAPSHOT:generate (generate-h2) on project jooq-test: Error running jOOQ code generation tool: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
[ERROR] - with linked exception:
[ERROR] [java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory]

Any ideas about the most reasonable way forward here, @nicolaiparlog / @wilkinsona ?

The fact that you don't see a NoClassDefFoundError for JAXBException means that the JAXB API was found and works properly. Looks like the implementation is missing, but I'm no JAXB user, so I don't know whether that's to be expected and what to do about it.

Yes, the API was found and worked properly, but then again, it won't be the JDK's API, so there might be ClassCastException between JAXB and JAXB from different modules, if users add the JAXB module to their module path. What a mess :-/

I guess the only proper solution would be to cross release a jOOQ JDK 8 and jOOQ JDK 9+ version.

While modularising a far simpler library (jOOX: https://github.com/jOOQ/jOOX/issues/153), I'm closing in on a solution here:

  1. JAXB isn't really used for anything significant in jOOQ, only for unmarshalling things like the code generator configuration or the runtime settings. That unmarshalling could be easily done manually as well
  2. The annotations can stay present on the JAXB-annotated objects. As far as I know, annotations that cannot be loaded by the class loader will simply be ignored. If they stay present, then the change in 1. (manual unmarshalling) would be backwards compatible, e.g. for the third-party gradle plugin, which reads the annotations. Up to them to figure out how to include the dependency.
  3. Compiling the annotations can be done by depending on the javax.xml.bind:jaxb-api dependency only. It's sufficient to add this dependency to the pom.xml, and the result will work for both Java 8 and 9

As far as I can tell, the above could even be implemented in a patch release, without breaking things. In jOOQ 3.11 (probably), we'll modularise jOOQ and stuff will work more naturally in jOOQ.

I've created an issue for this: #6879

Was this page helpful?
0 / 5 - 0 ratings