0

i have an application running in jdk17 that tries to use jaxb, but is failing to load the actual jaxb-runtime.jar, it seems.

I have added jaxb-api.jar 2.3.1 and jaxb-runtime.jar 2.3.4 to the classpath

And i have this code

try (BufferedReader br = new BufferedReader(new java.io.InputStreamReader(getClass().getResourceAsStream("/META-INF/services/javax.xml.bind.JAXBContext")))) {
    String cn = br.readLine();
    Class c = Class.forName(cn);
    System.out.println("Impl class: " + c.getName());
} catch (Exception e) {
    e.printStackTrace();
}

 context = JAXBContext.newInstance(getClass());

When run, i get

Impl class: com.sun.xml.bind.v2.ContextFactory

Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal bind.v2.ContextFactory
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122)
    at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276)

So this tells me that jaxb-runtime.jar is on the classpath, but for some reason, when the jaxb code goes to look for the correct Context Factory, it doesn't find the service lookup info, and just defaults to the default. (notice the .internal.)

If i add a jaxb.properties file and force it to pick my class, then it just CNFEs on com.sun.xml.bind.v2.ContextFactory

It's like there are two classloaders in play or something.

Anyone have any idea as to how to debug further?

MeBigFatGuy
  • 28,272
  • 7
  • 61
  • 66
  • 2
    Are you using a tool such as Maven or Gradle to manage your libraries? I believe there are transitive dependencies which are also needed as well as the `jaxb-api` and `jaxb-runtime` JARs. If you are just adding these 2 JARs to the classpath manually, you may be missing those extra JARs. [example](https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime/2.3.4) – andrewJames May 03 '22 at 00:58
  • that is a reasonable suggestion, and i expect that may happen later on, but service locator should work fine, and find the correct factory name. – MeBigFatGuy May 03 '22 at 13:57
  • Understood. I have not been able to recreate your specific problem. But as a quick test, can you add the old JAXB runtime JAR to your classpath - for example, `jaxb-impl-2.3.1.jar`, downloadable from [this page](https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl/2.3.1). That contains `com.sun.xml.bind.v2.ContextFactory`. – andrewJames May 03 '22 at 14:22
  • Or, similarly, try the Metro (reference implementation) JAXB runtime JAR (e.g. from [here](https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime/2.3.1)). – andrewJames May 03 '22 at 14:27

1 Answers1

2

I just encountered the same issue whilst trying to upgrade a project from Java 8 to Java 17.

Thanks to this I found what appears to be some very odd behaviour by the JAXB runtime to do with class loaders.

As a work-around I have wrapped all my JAXBContext.newInstance calls like this:

public interface Util {

// TODO see here: https://stackoverflow.com/questions/64979229/eclipse-osgi-java-11-jaxb-and-the-classloader
//  - without this the classloader breaks for Java >=9
default <T> Unmarshaller getUnmarshaller(Class<T> cl) throws JAXBException {
    Thread thread = Thread.currentThread();
    ClassLoader classLoader = thread.getContextClassLoader();
    try {
        thread.setContextClassLoader(getClass().getClassLoader());
        JAXBContext ctx = JAXBContext.newInstance(cl);
        return ctx.createUnmarshaller();
    } finally {
        thread.setContextClassLoader(classLoader);
    }
}

Also, as described here you need a file src/main/resources/jaxb.properties:

javax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory

I don't pretend to understand why this is necessary. It would be great if someone could explain, and perhaps suggest a better way to fix it.

HTH