当前位置: 首页 > 知识库问答 >
问题:

如何在osgi(Liferay DXP)中使用JAXB 2.2.11

郭修平
2023-03-14

此代码会导致具有以下堆栈跟踪的空指针异常

Caused by: java.lang.NullPointerException
    at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:129)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:201)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:146)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:371)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:446)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:409)

查看ContextFinder的源代码,我可以看到第129行的context必须为空:

抛出handleClassCastException(context.getClass(),jaxbcontext.class);

我认为问题可能是我的模块依赖于JAXB-API2.2.11,但是jaxb-impl类是由rt.jar在运行时提供的,并且可能比2.2.11新,因为Liferay DXP运行在JDK1.8上。为了解决这个问题,我尝试在osgi模块中包含jaxb-impl.jar2.2.11作为一个依赖项,并认为jaxb-api和jaxb-impl版本将与之相匹配。之后,尝试使用与上面相同的代码创建JAXBContent会导致以下错误:

ClassCastException: attempting to cast jar:file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/rt.jar!/javax/xml/bind/JAXBContext.class to bundleresource://623.fwk616113009:13/javax/xml/bind/JAXBContext.class. Please make sure that you are specifying the proper ClassLoader.

从这条消息的外观来看,被实例化的JAXBContext来自通过RT.jar加载的JAXBContext版本。这对我来说非常混乱,因为我希望使用模块的类加载器加载的JAXBContext版本,因为我在模块中包含了jaxb-impl.jar,并且我指定了模块的类加载器是在调用JAXBContext.newInstance时使用的。有谁能说明一下我如何让JAXB2.2.11在osgi容器中工作吗?

*请注意,我无法升级我的模块使用的jaxb-api版本,因为JAXB代码实际上在需要JAXB 2.2.11的第三方jar中(我刚刚通过编写一些测试JAXB代码从公式中消除了第三方jar)。

共有1个答案

曾皓
2023-03-14

经过广泛的研究,我找到了以下解决方案。由于传递bundle类加载器似乎是正确的,所以我尝试了这条路,弄清楚了为什么会得到NullPointerException(NullPointerException)。在仔细查看了jaxb-api的源代码以跟踪NullPointerException的堆栈跟踪之后,我可以看到jaxb-api代码执行以下操作:

ClassLoader.LoadClass(“com.sun.xml.internal.bind.v2.contextFactory”)

其中classloader是我的bundle的类加载器(因为这是我传入的),而contextFactory实际上是jaxb-impl中的一个类,由bootstrap类加载器加载。这就是问题所在,因为我的bundle的类加载器将无法看到由bootstrap类加载器加载的类。这让我有些困惑,因为我不习惯类加载器在OSGi中的工作方式。我错误地认为bootstrap类加载器加载的类是可见的,因为我已经习惯了有委派的web应用程序类加载。在osgi类加载器彼此完全隔离的情况下,只有在导出时,事物才是可见的。为了绕开这个问题,我找到了一些关于类似问题的有用帖子。原来在osgi中有一个叫做引导委托的概念,在这个概念中,您可以指定一个总是通过引导类加载器加载的类/包的列表。所以最终的结果是两步:

1)在调用代码获取JAXBContext之前,将线程的类加载器切换到绑定类加载器:

ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();

try {           
    // ObjectFactory here is in the same package as my classes to be marshalled
    ClassLoader objectFactoryClassLoader = ObjectFactory.class.getClassLoader();            
    Thread.currentThread().setContextClassLoader(objectFactoryClassLoader);
    // JAXB code goes here
} finally {
    Thread.currentThread().setContextClassLoader(currentClassLoader);
}

2)使用引导委派机制指定要加载的包。这个列表需要包括您需要加载的类的可传递依赖项。在我的例子中,我使用的是Liferay,所以列表是特定于Liferay的,并且放在portal-ext.properties配置文件中。幸运的是,我发现了这个帖子,其中有人为我做了大部分工作:

module.framework.properties.org.osgi.framework.bootdelegation=\
  __redirected,\
  com.liferay.aspectj,\
  com.liferay.aspectj.*,\
  com.liferay.portal.servlet.delegate,\
  com.liferay.portal.servlet.delegate*,\
  com.sun.ccpp,\
  com.sun.ccpp.*,\
  com.sun.crypto.*,\
  com.sun.image.*,\
  com.sun.jmx.*,\
  com.sun.jna,\
  com.sun.jndi.*,\
  com.sun.mail.*,\
  com.sun.management.*,\
  com.sun.media.*,\
  com.sun.msv.*,\
  com.sun.org.*,\
  com.sun.syndication,\
  com.sun.tools.*,\
  com.sun.xml.*,\
  com.yourkit.*,\
  org.eclipse.persistence.internal.jaxb,\
  org.eclipse.persistence.internal.jaxb.*,\
  javax.xml.*,\
  sun.*

有用的链接:

为什么在Apache Felix内部运行时,JAXB找不到我的JAXB.index?

osgi中的bootdelegation和DynamicImport-Package有什么区别

https://web.liferay.com/web/user.26526/blog/-/blogs/liferay-dxp-and-weblogic-

 类似资料:
  • 作为最新的Apache POI3.11,JAR不是bundle,让POI在OSGi中工作的最佳方式是什么? 我尝试了两种方法: 将JAR直接嵌入到唯一使用它们的包中 使用预包装为包的POI罐子 注意:至少还需要和,但它们已经是bundle了。 使用预包装的JAR,我尝试使用3.92。这还需要,所以我使用了预包装的,但这至少需要1.0版本,我的JVM/Felix OSGi将其宣传为“only”版本。

  • 我试图构建一个使用嵌入式OrientDB(当前为“Memory:”)图形数据库的应用程序。我用的是OrientDB2.2 orientdb-graphdb不应该依赖于一个合适的包,或者包括并导出类吗?

  • 我的问题在于在前端包中使用/消费来自下游节点包的服务(例如osgi-mobile使用/消费来自osgi-downstreamnode1的服务)。 我目前正在Eclipse Mars中构建它们,由于没有将整个osgi-downstreamnode1包打包到一个JAR中,并将其导入osgi-mobile包,所以我似乎不知道如何在Eclipse中引用这些包,以及如何让osgi-mobile包在运行时调用

  • 我在使用rome库创建RSS Feeds时遇到了一个问题。https://rometools.github.io/如果我只是将lib添加到我的pom.xml并将其部署到AEM实例,然后调用一个应该使用该库的servlet,它就会失败...我无法调试到servlet。 我认为这是一个类加载问题,在罗马工具的网站上有一个将系统属性“rome.pluginmanager.useloadclass”设置为

  • 我想使用这个java库[1]enj-library 我将这个库编译成jar,然后在eclipse下创建了一个新的插件项目“来自现有JAR档案的插件” 然后我试着将它添加到我的包,但它没有 2.我需要它作为添加包,但我得到了 3.我添加了类路径,我的包开始了,但我得到了类未找到异常 [1]https://github.com/dog 网关/enj-library 我在OSGI捆绑包包含这个库如何?

  • 问题内容: 我目前正在尝试获取一个包含Service Factory运行的简单捆绑包。 这是我的工厂班级: 这是我应该由工厂创建的服务: 最后是OSGI-INF / component.xml 如果我在春分内运行测试包(A,B和C),则会收到以下错误: 我找不到有关使用Internet上的组件定义中声明的ServiceFeactories的太多信息。甚至《 OSGi和Equinox》一书也没有告诉