cla*_*lav 3 osgi jaxb osgi-bundle liferay-7
我正在尝试在osgi环境(Liferay DXP)中使用JAXB 2.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)
Run Code Online (Sandbox Code Playgroud)
查看ContextFinder的源,我可以看到context
在第129行中该值必须为null:
throw handleClassCastException(context.getClass(), JAXBContext.class);
我认为问题可能是我的模块依赖于jaxb-api 2.2.11,但是jaxb-impl类是由rt.jar在运行时提供的,并且可能比2.2.11更新,因为Liferay DXP在JDK 1.8上运行。为了解决这个问题,我尝试将jaxb-impl.jar 2.2.11作为依赖项包含在我的osgi模块中,并认为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.
Run Code Online (Sandbox Code Playgroud)
根据此消息的外观,实例化的JAXBContext来自通过rt.jar加载的JAXBContext版本。这让我非常困惑,因为我希望使用模块的类加载器加载的JAXBContext版本,因为我已经在模块中包含jaxb-impl.jar,并且指定了模块的类加载器为我对JAXBContext.newInstance的调用。谁能阐明我如何使jaxb 2.2.11在osgi容器中工作?
*请注意,我无法升级模块所使用的jaxb-api的版本,因为JAXB代码实际上位于需要jaxb 2.2.11的第三方jar中(目前我刚刚从等式中删除了第三方jar通过编写一些测试JAXB代码)。
经过广泛的研究,我找到了以下解决方案。由于这似乎是通过捆绑类加载器在接受答案的建议这个职位必须是正确的,我也跟着弄清楚为什么我得到一个NullPointerException当我试图说的路径。在仔细查看了jaxb-api的源代码以遵循NullPointerException的堆栈跟踪之后,我可以看到jaxb-api代码做了类似的事情
classLoader.loadClass("com.sun.xml.internal.bind.v2.ContextFactory")
classLoader
我的包的类加载器在哪里(因为这是我传入的内容),ContextFactory
实际上是jaxb-impl中的一个类,由引导类加载器加载。这是问题所在,因为我的捆绑软件的类加载器将无法查看由引导类加载器加载的类。这让我有些烦恼,因为我不习惯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);
}
Run Code Online (Sandbox Code Playgroud)
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.*
Run Code Online (Sandbox Code Playgroud)
有用的网址:
在Apache Felix中运行时,为什么JAXB找不到我的jaxb.index?
osgi中的bootdelegation和DynamicImport-Package有什么区别
https://web.liferay.com/web/user.26526/blog/-/blogs/liferay-dxp-and-weblogic-
https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/bundle-classloading-flow
http://apache-felix.18485.x6.nabble.com/Classloading-for-JAXB-td4834670.html
归档时间: |
|
查看次数: |
1212 次 |
最近记录: |