When using the Hibernate JPA metamodel generator through the maven processor plugin on JDK 11 it can fail with a seeming ClassCastException on JAXBContext. This seems to come from a classloading issue where there are two JAXBContext class objects on different classloaders and the created JAXBContextImpl, which is a subclass of the one JAXBContext, can't be cast to the other JAXBContext.
During mvn compile of the relevant project (/module) the hibernate metamodel generator will fail with the message:
This of course means that, while the metamodel generator runs, it uses the default config since it can’t read the persistence.xml. Running with default config is unlikely to be either expected or wanted in a case where there is a persistence.xml
Digging a bit deeper I found out the cause was an XmlParsingException cause by a JAXBException:
(Note: The "ClassCastException" is part of the JAXBException's message. It is not a true ClassCastException, it is a JAXBException with a specially generated message. See the handleClassException method in jaxb-api's ContextFinder: https://github.com/eclipse-ee4j/jaxb-api/blob/797f8c8564df1dee944a0ca3ea3622d518e1ba71/jaxb-api/src/main/java/javax/xml/bind/ContextFinder.java#L108)
This message means that the created JAXBContextImpl can't be cast to JAXBContext, which is one of its superinterfaces. Normally, this can only happen if there are different variations of JAXBContext involved.
After coming at this problem from a number of different ways and excluding the most obvious causes of JAXBContext, such as different versions of the jaxb-api being on the classpath at the same time, I found out the exact same class file was being used for 'both' JAXBContexts. This turned was due to a classloader conflict. The JAXBContextImpl was generated on one classloader (which also loaded JAXBContext somewhere in its classloader hierarchy) but jaxb then tried to cast it to a JAXBContext that was loaded in a different classloader(-hierarchy).
It turns out this is due to the XmlParserHelper calling `JAXBContext.newInstance` without a classloader passed in, which results in jaxb using the current thread's context classloader, which is not correct in a maven plugin context. If I pass in the classloader used to load the current class (XmlParserHelper) instead the error disappears.
This seems to be caused by Java 11 no longer including the jaxb api classes. See https://github.com/eclipse-ee4j/jaxb-api/issues/99 for a related issue.
I'll try to add a testcase. Since this might be related to the way maven plugins do classloading in combination with jdk 11+ and I'm not that confident with gradle classloading/gradle plugins It'll probably be a maven based minimal project that reproduces the problem.)
I first saw this bug on 5.4.5, finally found the cause on 5.4.10 I don’t think anything relevant changed in between those two versions.
Linux (Ubuntu 19.10), OpenJDK 11.0.5 (build 11.0.5+10-post-Ubuntu-0ubuntu1.1), Maven 3.6.1
See attachment for a minimal maven project that reproduces the error. Just run mvn clean compile.
Note that the maven build won’t fail, since the metamodel generator will run with default settings. However you will see the warning in the maven log:
[INFO] diagnostic: Note: Hibernate JPA 2 Static-Metamodel Generator 5.4.10.Final [WARNING] diagnostic: warning: Unable to parse persistence.xml: Unable to perform unmarshalling at line number 0 and column 0. Message: null
Same problem here, the metamodel generator can’t instantiate a JAXB context although the correct dependencies are in the annotation processor’s classpath.