I am in the progress of migrating from Java 8 to Java 11.
There is one ANT task in our build that we need to create our database schema. The ANT task (org.hibernate.tool.hbm2ddl.SchemaExportTask) is part of the Hibernate ORM core library. The task depends on JAXB, which was part of the JDK before but was removed with Java 11.
Fortunately, the JAXB runtime is available as an external library, so let’s just add it to the ANT task classpath:
configurations {
hibtools
}
dependencies {
hibtools group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.1'
hibtools group: 'org.hibernate', name: 'hibernate-core', version: '5.3.6.Final'
}
task createSchema {
doLast {
ant.taskdef(name: 'schemaexport',
classname: 'org.hibernate.tool.hbm2ddl.SchemaExportTask',
classpath: configurations.hibtools.asPath)
// ......
}
}
So, it’s all good? Unfortunately, no:
[ant:schemaexport] java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory
[ant:schemaexport] at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
[ant:schemaexport] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
[ant:schemaexport] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
[ant:schemaexport] at org.hibernate.boot.cfgxml.internal.JaxbCfgProcessor.unmarshal(JaxbCfgProcessor.java:122)
After some debugging, I learned that javax.xml.bind.ContextFinder
tries to load the class com.sun.xml.bind.v2.ContextFactory
(which is on the ANT classpath!) using the “wrong” classloader. Instead of doing getClass().getClassLoader().loadClass("com.sun.xml.bind.v2.ContextFactory")
is does something like Thread.currentThread().getContextClassLoader().loadClass("com.sun.xml.bind.v2.ContextFactory")
, which throws a ClassNotFoundException.
The difference is that getClass().getClassLoader()
returns the AntClassLoader
that actually finds the JAXB runtime library. But Thread.currentThread().getContextClassLoader()
returns Gradles own org.gradle.internal.classloader.VisitableURLClassLoader
.
The class javax.xml.bind.ContextFinder
is part of the official JAXB-API library, so there is no way for me to change its implementation. So, what can I do? Is there any way to make the VisitableURLClassLoader find the JAXB runtime library?