我试图在osgi环境(Liferay )中使用JAXB2.2.11。我在创建JAXBContext时遇到了问题。基于在研究这和这时发现的其他来源,我确定在osgi容器中,我需要为JAXB提供正确的类加载器来实例化上下文。所以我有这样的代码:
ClassLoader cl package.with.jaxb.objects.ObjectFactory.class.getClassLoader(); JAXBContext jc = JAXBContext.newInstance("package.with.jaxb.objects ", cl);
此代码将导致具有以下堆栈跟踪的空指针异常:
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必须为null:
throw handleClassCastException(context.getClass(), JAXBContext.class);
我想问题可能是我的模块依赖jaxb 2.2.11,但是jaxb-impl类是由rt.jar在运行时提供的,并且可能比2.2.11更新,因为Liferay运行在JDK1.8上。为了解决这个问题,我尝试在我的osgi模块中将jaxb-bin.jar 2.2.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-in-.jar,并且我指定了我的模块的类加载器是在调用JAXBContext.newInstance时使用的。有人能说明我如何让jaxb2.2.11在osgi容器中工作吗?
*请注意,我无法升级我的模块使用的jaxb-api版本,因为JAXB代码实际上位于一个需要jaxb 2.2.11的第三方jar中(我刚刚编写了一些测试JAXB代码,从等式中删除了第三方jar )。
发布于 2017-10-05 15:08:40
经过广泛的研究,我找到了以下解决方案。由于这个职位中被接受的答案所建议的传递包类装入器似乎是正确的,所以我遵循了一条路径,即当我尝试时,我要找出为什么要得到一个NullPointerException。在仔细查看jaxb-api的源代码以跟踪NullPointerException的堆栈跟踪之后,我可以看到jaxb-api代码执行以下操作:
classLoader.loadClass("com.sun.xml.internal.bind.v2.ContextFactory")
其中,classLoader是我的包的类装入器(因为这是我传入的),而ContextFactory实际上是jaxb中的一个类,它是由引导类加载器加载的。这就是问题所在,因为我的包的类加载器将无法看到由引导类加载器加载的类。这让我有一段时间不适应osgi中类加载器的工作方式。我错误地认为引导类加载器加载的类是可见的,因为我习惯于在有委托的地方加载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的,它位于port-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.*有用的链接:
为什么JAXB在Apache中运行时找不到我的jaxb.index?
https://web.liferay.com/web/user.26526/blog/-/blogs/liferay-dxp-and-weblogic-
http://apache-felix.18485.x6.nabble.com/Classloading-for-JAXB-td4834670.html
发布于 2019-07-11 19:37:11
下面是使用JDK 11、Liferay DXP/7.2、OSGI和从Dev创建的示例Jax服务的解决方案。当我试图访问web服务时,我得到的错误如下:
JAXBException发生了:在模块路径或类路径上还没有找到JAXB的实现。org.apache.aries.jax.rs.whiteboard_1.0.4找不到com.sun.xml.内在.bind.v2.ContextFactory。
对我起作用的是在系统级别定义上下文工厂,以覆盖预定义的上下文工厂。将下列系统变量添加到系统中
javax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory例如,您可以将其添加到Tomcat中的setenv.sh/bat文件中,或者在eclipse中,您可以在VM参数下访问服务器启动配置参数选项卡
-Djavax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory由于Liferay已经包含了这些库,所以这样做并不需要添加任何额外的库。
这是怎么回事?请参阅用于JaxBContext的javadoc并阅读JAXB实现部分的发现。使用/META/services/javax.xml.bind.JAXBContext文件对我无效。
我希望这能帮上忙。对于DXP用户来说,最后一个注意事项是,如果您在服务上被拒绝了权限,那么您需要阅读有关服务访问策略的内容。
发布于 2017-10-04 05:58:41
查看应该如何完成的最佳位置是Apache。它没有安装任何JAXB包,而是在org.apache.servicemix.specs.jaxb-api-2.2-2.7.0.jar目录中使用lib/endorsed。
这样,您就不会使用rt.jar提供的JAXB。
对于实现,最好使用JAXB包的ServiceMix版本:
https://stackoverflow.com/questions/46554116
复制相似问题