Nicolai Parlog
2018-07-26 10:41:13 UTC
Hi!
TL;DR: On Java 10.0.1, a web app in Tomcat 9.0.8.0 has no access to JAXB
even though its reference implementation is present on the class path.
(This looks like a bug to me, but "Before you report a bug" urged me to
ask here first. :) )
NOTE: I already asked [on
StackOverflow](https://stackoverflow.com/q/51518781/2525313), where the
question is a little more readable.
On to the details...
# The Situation
We have a web app that runs on Tomcat and depends on JAXB. During our
migration to Java 9 we opted for adding [the JAXB reference
implementation as a regular
dependency](https://stackoverflow.com/a/48204154/2525313).
Everything worked when launching the app from the IDE [with embedded
Tomcat](https://tomcat.apache.org/tomcat-9.0-doc/api/org/apache/catalina/startup/Tomcat.html),
but when running it on a real Tomcat instance, I get this error:
Caused by: java.lang.RuntimeException: javax.xml.bind.JAXBException:
Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException:
com.sun.xml.internal.bind.v2.ContextFactory]
at [... our-code ...]
Caused by: javax.xml.bind.JAXBException: Implementation of JAXB-API has
not been found on module path or classpath.
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:278)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:421)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
~[jaxb-api-2.3.0.jar:2.3.0]
at [... our-code ...]
Caused by: java.lang.ClassNotFoundException:
com.sun.xml.internal.bind.v2.ContextFactory
at
jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
~[?:?]
at
jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
~[?:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:499) ~[?:?]
at
javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122)
~[jaxb-api-2.3.0.jar:2.3.0]
at
javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:421)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
~[jaxb-api-2.3.0.jar:2.3.0]
at [... our-code ...]
jaxb-api-2.3.0.jar
jaxb-core-2.3.0.jar
jaxb-impl-2.3.0.jar
What is going on here?
# What I tried
## Adding JARs
Maybe it helps to add the JARs to Tomcat's class path in `setenv.sh`?
CLASSPATH=
.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/jaxb-impl-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/jaxb-core-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/javax.activation-1.2.0.jar
Nope:
Caused by: javax.xml.bind.JAXBException: ClassCastException: attempting
to cast
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bind/JAXBContext.class to
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bind/JAXBContext.class.
Please make sure that you are specifying the proper ClassLoader.
at
javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:157)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:300)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:286)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:409)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
~[jaxb-api-2.3.0.jar:2.3.0]
at
de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.initializeCommandExtractor(DefaultWmsRequestFactory.java:103)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
at
de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.lambda$new$0(DefaultWmsRequestFactory.java:87)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
That's clearly the same class, so apparently it has been loaded by two
class loaders. I suspect [the system class loader and the app's class
loader](https://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html#Class_Loader_Definitions),
but why would loading `JAXBContext` be delegated to the system class
loader once but not always? It almost looks as if the delegation
behavior of the app's class loader changes while the program runs.
## Adding the module
I don't really want to add _java.xml.bind_, but I tried it anyways by
adding this to `catalina.sh`:
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"
Doesn't work either, though:
Caused by: java.lang.ClassCastException:
java.xml.bind/com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
cannot be cast to com.sun.xml.bind.v2.runtime.JAXBContextImpl
at [... our-code ...]
Apart from the different class and stack trace, this is in line with
what happened earlier: The class `JAXBContextImpl` was loaded twice,
once from _java.xml.bind_ (must have been the system class loader) and
one other time (I assume by the app's loader from the JAR).
## Searching for bugs
[Searching Tomcat's bug
database](https://bz.apache.org/bugzilla/query.cgi) I found
[#62559](https://bz.apache.org/bugzilla/show_bug.cgi?id=62559). Could
that be the same error?
--
PGP Key:
http://keys.gnupg.net/pks/lookup?op=vindex&search=0xCA3BAD2E9CCCD509
Web:
http://blog.codefx.org
a blog about software development
https://courses.codefx.org
high-quality Java courses
Social:
https://twitter.com/nipafx
http://youtube.com/c/codefx
---------------------------------------------------------------------
To unsubscribe, e-mail: users-***@tomcat.apache.org
For additional commands, e-mail: users-***@tomcat.apache.org
TL;DR: On Java 10.0.1, a web app in Tomcat 9.0.8.0 has no access to JAXB
even though its reference implementation is present on the class path.
(This looks like a bug to me, but "Before you report a bug" urged me to
ask here first. :) )
NOTE: I already asked [on
StackOverflow](https://stackoverflow.com/q/51518781/2525313), where the
question is a little more readable.
On to the details...
# The Situation
We have a web app that runs on Tomcat and depends on JAXB. During our
migration to Java 9 we opted for adding [the JAXB reference
implementation as a regular
dependency](https://stackoverflow.com/a/48204154/2525313).
Everything worked when launching the app from the IDE [with embedded
Tomcat](https://tomcat.apache.org/tomcat-9.0-doc/api/org/apache/catalina/startup/Tomcat.html),
but when running it on a real Tomcat instance, I get this error:
Caused by: java.lang.RuntimeException: javax.xml.bind.JAXBException:
Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException:
com.sun.xml.internal.bind.v2.ContextFactory]
at [... our-code ...]
Caused by: javax.xml.bind.JAXBException: Implementation of JAXB-API has
not been found on module path or classpath.
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:278)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:421)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
~[jaxb-api-2.3.0.jar:2.3.0]
at [... our-code ...]
Caused by: java.lang.ClassNotFoundException:
com.sun.xml.internal.bind.v2.ContextFactory
at
jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
~[?:?]
at
jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
~[?:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:499) ~[?:?]
at
javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122)
~[jaxb-api-2.3.0.jar:2.3.0]
at
javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:421)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
~[jaxb-api-2.3.0.jar:2.3.0]
at [... our-code ...]
Implementation of JAXB-API has not been found on module path or classpath.
These are the relevant files in `webapps/$app/WEB-INF/lib`:jaxb-api-2.3.0.jar
jaxb-core-2.3.0.jar
jaxb-impl-2.3.0.jar
What is going on here?
# What I tried
## Adding JARs
Maybe it helps to add the JARs to Tomcat's class path in `setenv.sh`?
CLASSPATH=
.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/jaxb-impl-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/jaxb-core-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/javax.activation-1.2.0.jar
Nope:
Caused by: javax.xml.bind.JAXBException: ClassCastException: attempting
to cast
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bind/JAXBContext.class to
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bind/JAXBContext.class.
Please make sure that you are specifying the proper ClassLoader.
at
javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:157)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:300)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:286)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:409)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
~[jaxb-api-2.3.0.jar:2.3.0]
at
de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.initializeCommandExtractor(DefaultWmsRequestFactory.java:103)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
at
de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.lambda$new$0(DefaultWmsRequestFactory.java:87)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
That's clearly the same class, so apparently it has been loaded by two
class loaders. I suspect [the system class loader and the app's class
loader](https://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html#Class_Loader_Definitions),
but why would loading `JAXBContext` be delegated to the system class
loader once but not always? It almost looks as if the delegation
behavior of the app's class loader changes while the program runs.
## Adding the module
I don't really want to add _java.xml.bind_, but I tried it anyways by
adding this to `catalina.sh`:
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"
Doesn't work either, though:
Caused by: java.lang.ClassCastException:
java.xml.bind/com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
cannot be cast to com.sun.xml.bind.v2.runtime.JAXBContextImpl
at [... our-code ...]
Apart from the different class and stack trace, this is in line with
what happened earlier: The class `JAXBContextImpl` was loaded twice,
once from _java.xml.bind_ (must have been the system class loader) and
one other time (I assume by the app's loader from the JAR).
## Searching for bugs
[Searching Tomcat's bug
database](https://bz.apache.org/bugzilla/query.cgi) I found
[#62559](https://bz.apache.org/bugzilla/show_bug.cgi?id=62559). Could
that be the same error?
--
PGP Key:
http://keys.gnupg.net/pks/lookup?op=vindex&search=0xCA3BAD2E9CCCD509
Web:
http://blog.codefx.org
a blog about software development
https://courses.codefx.org
high-quality Java courses
Social:
https://twitter.com/nipafx
http://youtube.com/c/codefx
---------------------------------------------------------------------
To unsubscribe, e-mail: users-***@tomcat.apache.org
For additional commands, e-mail: users-***@tomcat.apache.org