title: JAXB not available on Tomcat 9 and Java 9/10
body: <p><strong>TLDR</strong>: On Java 9/10, a web app in Tomcat has no access to JAXB even though its reference implementation is present on the class path.</p>
  
  <p><strong>Edit</strong>: No, this is not a duplicate of <a href="https://stackoverflow.com/q/43574426/2525313">How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException in Java 9</a> - as you can tell by the <em>What I tried</em> section, I already tried the proposed solutions.</p>
  
  <h1>The Situation</h1>
  
  <p>We have a web app that runs on Tomcat and depends on JAXB. During our migration to Java 9 we opted for adding <a href="https://stackoverflow.com/a/48204154/2525313">the JAXB reference implementation as a regular dependency</a>.</p>
  
  <p>Everything worked when launching the app from the IDE <a href="https://tomcat.apache.org/tomcat-9.0-doc/api/org/apache/catalina/startup/Tomcat.html" rel="noreferrer">with embedded Tomcat</a>, but when running it on a real Tomcat instance, I get this error:</p>
  
  <pre><code>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 ...]
  </code></pre>
  
  <p>Note:</p>
  
  <blockquote>
    <p>Implementation of JAXB-API has not been found on module path or classpath.</p>
  </blockquote>
  
  <p>These are the relevant files in <code>webapps/$app/WEB-INF/lib</code>:</p>
  
  <pre><code>jaxb-api-2.3.0.jar
  jaxb-core-2.3.0.jar
  jaxb-impl-2.3.0.jar
  </code></pre>
  
  <p>What is going on here?</p>
  
  <h1>What I tried</h1>
  
  <h2>Adding JARs to Tomca's <code>CLASSPATH</code></h2>
  
  <p>Maybe it helps to add the JARs to Tomcat's class path in <code>setenv.sh</code>?</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Nope:</p>
  
  <pre><code>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]
  </code></pre>
  
  <p>That's clearly the same class, so apparently it has been loaded by two class loaders. I suspect <a href="https://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html#Class_Loader_Definitions" rel="noreferrer">the system class loader and the app's class loader</a>, but why would loading <code>JAXBContext</code> 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.</p>
  
  <h2>Adding the module</h2>
  
  <p>I don't really want to add <em>java.xml.bind</em>, but I tried it anyways by adding this to <code>catalina.sh</code>:</p>
  
  <pre><code>JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"
  </code></pre>
  
  <p>Doesn't work either, though:</p>
  
  <pre><code>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 ...]
  </code></pre>
  
  <p>Apart from the different class and stack trace, this is in line with what happened earlier: The class <code>JAXBContextImpl</code> was loaded twice, once from <em>java.xml.bind</em> (must have been the system class loader) and one other time (I assume by the app's loader from the JAR).</p>
  
  <h2>Searching for bugs</h2>
  
  <p><a href="https://bz.apache.org/bugzilla/query.cgi" rel="noreferrer">Searching Tomcat's bug database</a> I found <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=62559" rel="noreferrer">#62559</a>. Could that be the same error?</p>
  
  <h2>Adding JAR's to Tomcat's <code>lib</code></h2>
  
  <p>Following <a href="http://mail-archives.apache.org/mod_mbox/tomcat-users/201807.mbox/%3cb1ca948e-f8d3-5c5e-9aaf-0c8c6c9f84d0@christopherschultz.net%3e" rel="noreferrer">advice given on the Tomcat user mailing list</a>, I added the JAXB JARs to Tomcat's <code>CATALINA_BASE/lib</code> directory, but got the same error as in the application's lib folder.</p>