gpt4 book ai didi

java - JAXB 在 Tomcat 9 和 Java 9/10 上不可用

转载 作者:太空狗 更新时间:2023-10-29 22:34:55 30 4
gpt4 key购买 nike

TLDR:在 Java 9/10 上,Tomcat 中的网络应用无法访问 JAXB,即使它的引用实现存在于类路径中也是如此。

编辑:不,这不是How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException in Java 9 的副本- 正如您在我尝试过的部分所知道的那样,我已经尝试了建议的解决方案。

情况

我们有一个在 Tomcat 上运行并依赖于 JAXB 的 Web 应用程序。在迁移到 Java 9 期间,我们选择添加 the JAXB reference implementation as a regular dependency .

从 IDE 启动应用程序时一切正常 with embedded Tomcat ,但是在真正的 Tomcat 实例上运行它时,出现此错误:

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.

这些是 webapps/$app/WEB-INF/lib 中的相关文件:

jaxb-api-2.3.0.jar
jaxb-core-2.3.0.jar
jaxb-impl-2.3.0.jar

这是怎么回事?

我尝试了什么

将 JAR 添加到 Tomca 的 CLASSPATH

也许在 setenv.sh 中将 JAR 添加到 Tomcat 的类路径中会有所帮助?

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

没有:

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]

这显然是同一个类,所以显然它已被两个类加载器加载。我怀疑the system class loader and the app's class loader ,但为什么将加载 JAXBContext 委托(delegate)给系统类加载器一次而不是总是?看起来应用程序的类加载器的委托(delegate)行为似乎在程序运行时发生了变化。

添加模块

我真的不想添加 java.xml.bind,但我还是尝试了,将其添加到 catalina.sh:

JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"

不过也行不通:

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 ...]

除了不同的类和堆栈跟踪之外,这与之前发生的情况一致:类 JAXBContextImpl 被加载了两次,一次来自 java.xml.bind (一定是系统类加载器)和另一次(我假设来自 JAR 的应用程序加载器)。

寻找错误

Searching Tomcat's bug database我找到了 #62559 .那会是同样的错误吗?

将 JAR 添加到 Tomcat 的 lib

正在关注 advice given on the Tomcat user mailing list ,我将 JAXB JAR 添加到 Tomcat 的 CATALINA_BASE/lib 目录,但出现了与应用程序的 lib 文件夹中相同的错误。

最佳答案

分析

首先是一些随机事实:

  • 如果不是given a class loader , JAXBContext::newInstance 将使用 the thread's context class loader在寻找 JAXB 实现时 - 即使您调用 newInstance(Class...) 也是如此(人们可能会错误地认为它使用提供的类实例的加载器)
  • Tomcat 构建 a small class loader hierarchy将 Web 应用程序彼此分开
  • 通过不依赖模块 java.xml.bind,在 Java 9 中,JAXB 类不会被 Bootstrap 或系统类加载器加载

下面是 Java 8 上发生的事情:

  • 我们没有将类加载器传递给 JAXB(糟糕),因此它使用线程的上下文类加载器
  • 我们的推测是 Tomcat 没有显式设置上下文类加载器,因此它最终将成为加载 Tomcat 的同一类加载器:系统类加载器
  • 这很不错,因为系统类加载器看到了整个 JDK,因此 JAXB 实现包含在其中

Java 9 进入 - 钢琴停止演奏,每个人都放下威士忌:

  • 我们添加了JAXB as a regular dependency因此它由网络应用程序的类加载器加载
  • 就像在 Java 8 上一样,JAXB 会搜索系统类加载器,但它看不到应用程序的加载器(只能反过来)
  • JAXB 无法找到实现并崩溃

解决方案

解决方案是确保 JAXB 使用正确的类加载器。我们知道三种方式:

  • 调用 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); 但这并不是一个好主意
  • 创建a context resolver ,但这需要 JAX-WS,感觉就像用另一种邪恶代替了一种邪恶
  • 使用 JAXBContext::newInstance ( Javadoc from Java EE 7 ) 的包接受变体,它也采用类加载器并传递正确的加载器,尽管这需要一些重构

我们使用了第三个选项并重构为 JAXBContext::newInstance 的包接受变体。琐碎的工作,但解决了问题。

注意事项

User curlals提供了关键信息,但删除了他们的答案。我希望这不是因为我要求进行一些编辑。所有的功劳/业力都应该归于他们! @curlals:如果您恢复并编辑您的答案,我会接受并点赞。

关于java - JAXB 在 Tomcat 9 和 Java 9/10 上不可用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51518781/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com