Discussion:
JAXB not available on Tomcat 9 and Java 10
Nicolai Parlog
2018-07-26 10:41:13 UTC
Permalink
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 ...]
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
Christopher Schultz
2018-07-26 15:37:21 UTC
Permalink
Nicolai Parlog
2018-07-27 14:36:17 UTC
Permalink
Hi Christopher,

unfortunately that didn't change the observable behavior - exact same
error message as when the JARs were in the application's lib folder.

so long ... Nicolai
Nicolai,
Post by Nicolai Parlog
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/catali
na/startup/Tomcat.html),
Post by Nicolai Parlog
javax.xml.bind.JAXBException: Implementation of JAXB-API has not
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)
com.sun.xml.internal.bind.v2.ContextFactory at
jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.ja
va:582)
~[?:?]
Post by Nicolai Parlog
at
jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders
.java:190)
~[?:?]
Post by Nicolai Parlog
at java.lang.ClassLoader.loadClass(ClassLoader.java:499) ~[?:?]
at
javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.j
ava:122)
~[jaxb-api-2.3.0.jar:2.3.0]
Post by Nicolai Parlog
at
155)
~[jaxb-api-2.3.0.jar:2.3.0]
Post by Nicolai Parlog
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 ...]
Post by Nicolai Parlog
Implementation of JAXB-API has not been found on module path
or classpath.
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`?
.../webapps/$app/WEB-INF/lib/javax.activation-1.2.0.jar
attempting to cast
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bi
nd/JAXBContext.class
Post by Nicolai Parlog
to
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bi
nd/JAXBContext.class.
Please make sure that you are specifying the proper ClassLoader.
Post by Nicolai Parlog
at
javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.ja
va:157)
~[jaxb-api-2.3.0.jar:2.3.0]
Post by Nicolai Parlog
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.initializeCo
mmandExtractor(DefaultWmsRequestFactory.java:103)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
Post by Nicolai Parlog
at
de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.lambda$new$0
(DefaultWmsRequestFactory.java:87)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
Post by Nicolai Parlog
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.ht
ml#Class_Loader_Definitions),
but why would loading `JAXBContext` be delegated to the system
class
Post by Nicolai Parlog
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
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"
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?
You will likely need to include these classes in Tomcat's
CATALINA_BASE/lib directory; it appears that placing them into
your application is causing some confusion.
You should not put any JAR files that are bundled into your
application into Tomcat's CLASSPATH. Better to simply move the
JARs from your application's WEB-INF/lib directory to Tomcat's
CATALINA_BASE/lib directory and make no changes to the CLASSPATH.
-chris
---------------------------------------------------------------------
--
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
Mark Thomas
2018-08-01 16:00:38 UTC
Permalink
Post by Nicolai Parlog
Hi Christopher,
unfortunately that didn't change the observable behavior - exact same
error message as when the JARs were in the application's lib folder.
Java 10.0.2
Tomcat 9.0.11-dev

I added the following to WEB-INF/lib:
activation-1.1.1.jar
jaxb-api-2.3.0.jar
jaxb-core-2.3.0.1.jar
jaxb-impl-2.3.0.1.jar

And then the following JSP worked:
<%
javax.xml.bind.JAXBContext.newInstance(org.apache.catalina.users.MemoryUser.class);
%>

I suggest the following:

Produce the smallest, simplest JSP that reproduces the problem with the
above libraries and then we can look at this further.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-***@tomcat.apache.org
For additional commands, e-mail: users-***@tomcat.apache.org
Nicolai Parlog
2018-08-08 05:17:10 UTC
Permalink
Hi,

with the help of an answer on StackOverflow we have solved this. In
case anybody was watching this, here's what happened...

First some random facts:

* if not given a class loader
(https://javaee.github.io/jaxb-v2/doc/user-guide/ch06.html#d0e6919),
`JAXBContext::newInstance` will use [the thread's context class
loader
(https://docs.oracle.com/javase/10/docs/api/java/lang/Thread.html#getContextClassLoader())
when looking for the JAXB implementation - this is the case even if
you call `newInstance(Class...)` (one might mistakenly think it uses
the provided class instances' loader)
* Tomcat builds a small class loader hierarchy
(https://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html)
to separate web applications from one another
* by not relying on the module _java.xml.bind_, in Java 9, JAXB
classes are not loaded by the bootstrap or system class loader

So here's what happened on Java 8:

* we don't pass a class loader to JAXB (oops), so it uses the
thread's context class loader
* our conjecture is that Tomcat does not explicitly set the context
class loader and so it will end up being the same one that loaded
Tomcat: the system class loader
* that's dandy because the system class loader sees the entire JDK
and hence the JAXB implementation included therein

Java 9 enters - the piano stops playing and everybody puts down their
scotch:

* we added JAXB as a regular dependency
(https://stackoverflow.com/a/48204154/2525313) and so it is
loaded by the web app's class loader
* just as on Java 8, JAXB searches the system class loader, though,
and that one can't see the app's loader (only the other way around)
* JAXB fails to find the implementation and goes belly up

The solution is to make sure JAXB uses the right class loader. We know
of three ways:

* call

`Thread.getCurrentThread().setContextClassLoader(this.getClass().getClassLoader());`
but that's not really a good idea
* create a context resolver

(https://docs.oracle.com/javaee/7/api/javax/ws/rs/ext/ContextResolver.html),
but that requires JAX-WS and that feels like replacing one evil with
another
* use the package-accepting variant of `JAXBContext::newInstance` that
also takes a class loader and pass the correct loader, although that
requires some refactoring

so long ... Nicolai
Post by Nicolai Parlog
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),
javax.xml.bind.JAXBException: Implementation of JAXB-API has not
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)
com.sun.xml.internal.bind.v2.ContextFactory at
jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
~[?:?]
Post by Nicolai Parlog
at
jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
~[?:?]
Post by Nicolai Parlog
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]
Post by Nicolai Parlog
at
javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155)
~[jaxb-api-2.3.0.jar:2.3.0]
Post by Nicolai Parlog
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 ...]
Post by Nicolai Parlog
Implementation of JAXB-API has not been found on module path or classpath.
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`?
.../webapps/$app/WEB-INF/lib/javax.activation-1.2.0.jar
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.
Post by Nicolai Parlog
at
javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:157)
~[jaxb-api-2.3.0.jar:2.3.0]
Post by Nicolai Parlog
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]
Post by Nicolai Parlog
at
de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.lambda$new$0(DefaultWmsRequestFactory.java:87)
~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
Post by Nicolai Parlog
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
Post by Nicolai Parlog
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
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"
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
Christopher Schultz
2018-08-09 17:34:44 UTC
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Nicolaj,
Post by Nicolai Parlog
Hi,
with the help of an answer on StackOverflow we have solved this.
In case anybody was watching this, here's what happened...
* if not given a class loader
(https://javaee.github.io/jaxb-v2/doc/user-guide/ch06.html#d0e6919),
`JAXBContext::newInstance` will use [the thread's context class
Post by Nicolai Parlog
loader
(https://docs.oracle.com/javase/10/docs/api/java/lang/Thread.html#getC
ontextClassLoader())
when looking for the JAXB implementation - this is the case even if
Post by Nicolai Parlog
you call `newInstance(Class...)` (one might mistakenly think it
uses the provided class instances' loader) * Tomcat builds a small
class loader hierarchy
(https://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html)
to separate web applications from one another * by not relying on
the module _java.xml.bind_, in Java 9, JAXB classes are not loaded
by the bootstrap or system class loader
* we don't pass a class loader to JAXB (oops), so it uses the
thread's context class loader * our conjecture is that Tomcat does
not explicitly set the context class loader and so it will end up
being the same one that loaded Tomcat: the system class loader
This is almost certainly an incorrect assumption. While an application
is processing a request, the TCCL should be that of the webapp's
ClassLoader. Any other situation would be a security problem.
Post by Nicolai Parlog
* that's dandy because the system class loader sees the entire JDK
and hence the JAXB implementation included therein
Java 9 enters - the piano stops playing and everybody puts down
* we added JAXB as a regular dependency
(https://stackoverflow.com/a/48204154/2525313) and so it is loaded
by the web app's class loader * just as on Java 8, JAXB searches
the system class loader, though, and that one can't see the app's
loader (only the other way around)
If your above assumption were true, then this would be true. But I
believe both of these assumptions are false.

It's easy to test your hypothesis: just print the value of the TCCL at
the point where you think JAXB is using the wrong one. If it's a
WebappClassLoader, then your analysis above is incorrect.

If it's printing the (somewhat confusingly called the) "application"
ClassLoader or "system" classloader, or "null", then something running
in your environment has broken the TCCL, and it's probably no Tomcat's
fault.
Post by Nicolai Parlog
* JAXB fails to find the implementation and goes belly up
The solution is to make sure JAXB uses the right class loader. We
* call
`Thread.getCurrentThread().setContextClassLoader(this.getClass().getCl
assLoader());`
but that's not really a good idea
Post by Nicolai Parlog
* create a context resolver
(https://docs.oracle.com/javaee/7/api/javax/ws/rs/ext/ContextResolver.
html),
but that requires JAX-WS and that feels like replacing one evil with
Post by Nicolai Parlog
another * use the package-accepting variant of
`JAXBContext::newInstance` that also takes a class loader and pass
the correct loader, although that requires some refactoring
JAXB using the TCCL is entirely appropriate. You need to find out why
the TCCL is wrong.

Try running your application under a SecurityManager and you'll find
out where the TCCL is being set pretty quickly :)

- -chris
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAltsezMACgkQHPApP6U8
pFh76BAAlFiN/qNZm5LSXRAriskFn3HMl6+dNdxzQt8xhVJAIvZt9yE+ntA6RMYd
vcXGCR/Ttb/f1wKGxKK6sfgifGWJXuL6+XRL6n0DaKicAN9euGY8qZh2wxarp0Aa
wa38zY1PemREkPpJZWphwT1jl/XCXzg/d7k+DCmcOMnKoAtGeH/J/AU18ay5dk97
FfDtVSSbMcp1R0QYNkC9rVta7A1cSgzVVnGHzu6sia7KViiG1/3f5yJEM3NlI9pe
EYKzo0N2h901TMDpv81NhGs0qeTkQQZHojtQsg7GWs29DQMXNeBP/Wv/ciuriuHA
B0E+NtS3MJRY2LZ3XTBPx3BvSY5giUGolt7tU6LDtKEMuiDMFkCrtdi5Useo1BTt
OJZxaphzuqPG94DhsO5b4/t9hNuZ1YurKZDcQ7j2UkI9/TwPiW33ch7T6qzIn6ZO
vKi/AAZQsYuOyGEOb7UZj8N2PFMXLXkbv+WX+QtvbnEM/0+s4AHejvxlcLE6I3k3
gUoHwqV+MXccZeEfgKgZm5xURES4AynBXR4BGMbUk6VZOryAVP80G3GKnkebNaK/
RrR0f4WbHDRKOp0azRFDWqmjkKwb4dYJTUWX8hhw1M4oTxRoiJx0pvcjK49sgkaH
Fx8MXxhCp00mWY4sOysXtNrHc+Tw8qvonFpO0juLc65/ttSafpI=
=GGUk
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-***@tomcat.apache.org
For additional commands, e-mail: users-***@tomcat.apache.org

Loading...