在我们的应用程序中,有时会出现以下异常:
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]
我们已经发现只有在使用Collection.parallelStream()
时才会发生这种情况,而在使用Collection.stream()
时则不会发生。
我们看到JAXB使用Thread.currentThread().getContextClassLoader()
来加载类。我们还看到,在使用parallelStream()
时,用于执行命令的线程正在使用不同的类加载器。有时是org.apache.catalina.loader.WebappClassLoader
,有时是jdk.internal.loader.ClassLoaders.AppClassLoader
。
现在看来,AppClassLoader
不了解JAXB依赖关系,而WebappClassLoader
却知道。
我们正在使用Java 11和以下Maven依赖项:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
有什么主意吗? AppClassLoader
怎么可能不了解我们的依赖关系?
答案 0 :(得分:9)
我们有不同的经历。问题在于,tomcat的类加载器与每次战争都不一样(我认为我们在Spring Boot应用程序中看到了类似的东西; void-main与应用程序运行器的情况有所不同)。.
无论哪种方式,问题都是“ bootstrap”类加载器无法访问应用程序中的jar,因此没有jaxb。因此,如果您曾经启动线程(例如来自ForkJoinPoolThread
或StreamXX.parallel()
的{{1}},那么这些线程将来自引导类加载器,而不是应用程序的类加载器。)因此,如果您是第一次使用背景任务加载JAXB,它们将运行ForkJoinPool.commonThreadPool()
并且找不到资源。
我们的解决方案是在一个显式线程池中启动所有后台任务,并建立一个显式线程池工厂。线程池工厂从调用线程(由war或spring初始化的线程)中捕获类加载器。 -boot上下文)。该类加载器将具有jaxb和朋友。.因此,现在从该线程池工厂启动的每个线程都有一个显式的getClass().getContextClassLoader().getResourceAsStream("xxxx")
....
问题(通过黑客入侵)
答案 1 :(得分:1)
您正在从某处加载旧版本的JAXB。在Java 11中,上下文工厂应为:
com.sun.xml.bind.v2.ContextFactory
不是
com.sun.xml.internal.bind.v2.ContextFactory
https://github.com/eclipse-ee4j/jaxb-api/issues/78
尝试执行以下操作: 将您的激活包升级到1.2。不确定它与它有什么关系,但是由于您使用的是Java 11,我建议您使用激活1.2
不是插入jaxB的glassfish实现。使用以下依赖项:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
或交替
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
如果仍然无法解决问题,请回退到我写给你的第一件事:
正确的上下文工厂是:
com.sun.xml.bind.v2.ContextFactory
在那儿有一个旧的装满的东西。
答案 2 :(得分:0)
我遇到了类似的问题,我正在为org.apache.xerces.parsers.SAXParser
获取ClassNotFoundException。我已经删除了/排除了xercesImpl
,xml-api
,xmlbeans
,xmlschema-core
的依赖关系,尽管我不知道它为什么以及如何工作,但该问题已解决。促使我删除这些jar的是JDK 8
和xml-api
中存在的XMLReaderFactory。
答案 3 :(得分:0)
此类com.sun.xml.internal.bind.v2.ContextFactory
以前在文件rt.jar
中可用,直到java 8
,然后从jdk
中删除。
可能的原因::您的应用程序使用了一些库,该库使用了一些旧库,期望使用java 8
,其中包含xml.bind
,该库已从{{1}中删除}。
解决方法::您可以简单地从jdk 11
复制文件/usr/lib/jvm/jre-1.8.0-openjdk/lib/rt.jar
,修剪其中的内容,仅保存jdk 8
包。然后将此com.sun.xml.internal.bind.*
放入您的jar
文件夹中。
答案 4 :(得分:0)