在jira中使用jaxb api失败的java类:提供者com.sun.xml.bind.v2.ContextFactory未找到

我正在为Jira编写一个插件,它涉及解析XML文档。 我正在使用JAXB这样做(XML to pojos,反之亦然)所以有一个类使用JAXB从pojos生成XML。 看起来像…

import javax.xml.bind.*; Class Parser { public void m1() { ... // code which uses classes in javax.xml.bind.* } public static void main(String args[]){ Parser p=new Parser(); p.m1(); } } 

提到的包将随JDK发行版(rt.jar)一起提供。 所以我还没有做任何其他的事情去上课。

当我使用’java’从命令行启动它时,它正常工作。 但是,当我把它打包成一个jar子并把它作为插件放在Jira中时它失败并出现以下错误

 javax.xml.bind.JAXBException: Provider com.sun.xml.bind.v2.ContextFactory not found - with linked exception: [java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory] at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:152) at javax.xml.bind.ContextFinder.find(ContextFinder.java:299) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337) 

这是在同一台机器上。 只有我能看到的差异不同于从命令行启动,当我在Jira中部署它时,它不是通过实例化调用main()而是调用m1()。

我想知道发生了什么! 它在同一台机器上。 我不知道Jira如何启动应用程序(因为我从命令行启动)。

com.sun.xml.bind包是JAXB RI( http://jaxb.dev.java.net/ )的一部分,所以你可能在你的类路径上有这个。

Java6在com.sun.xml.internal.bind包中包含它自己的JAXB版本,因此您通常不需要Java6中的RI。

RI 可以与Java6一起使用,但这是一场艰苦的战斗,通常会遇到这类问题。

我知道这是一个迟到的答案,但对于登陆这里的人来说,在为JIRA(以及其他Atlassian产品)开发插件时,其他post中没有提及的一些内容非常重要。

第一个JIRA,或者更确切地说是Atlassian,有两种类型的插件,请参阅插件1和插件2 之间的差异

由于它是ClassNotFoundException(和JIRA v4.0.1),我假设插件是Plugin2,可以在JIRA v4及更高版本中使用。

从JIRA v4开始,JIRA充当OSGi容器,因此Plugin2是一个OSGi包。 在OSGi中,每个bundle都有自己的一组类加载器。 这使得不同的捆绑包具有相同jar的不同版本,并且可以进行热部署等。 但问题是,并非JDK的所有软件包都默认可用于这些类加载器。 这在Atlassian Developers网页上的插件,包和OSGi下进行了解释。 更详细的描述可以在博客Exourceing OSGi中的引导类路径博客中找到。 第二段甚至有标题NoClassDefFoundError:com.sun …

理论如此之多。

在使用Atlassian SDK开发JIRA插件时,Maven在幕后使用,请参阅Atlassian Plugin SDK文档 。 所以插件项目中会有一个pom.xml。 要在插件中包含JDK包,可以将一个标记添加到maven-jira-plugin (对于其他Atlassian产品,有一个相应的maven插件),并设置bootdelegation属性(您可能想要设置java for 1.6 for maven-compiler-plugin ):

 ...    com.atlassian.maven.plugins maven-jira-plugin 3.7.3 true  ${jira.version} ${jira.data.version}   atlassian.org.osgi.framework.bootdelegation sun.*,com.sun.*      maven-compiler-plugin  1.6 1.6   ...   ... 

然后列出的包将可用于捆绑包。 但请注意,启动委派不是解决所有问题的解决方案,只应与限制一起使用。 阅读引导委派和避免类加载器黑客的更多内容 。

在依赖项下,可以设置所需的jaxb-api版本:

 ...   com.atlassian.jira atlassian-jira ${jira.version} provided   com.atlassian.plugins.rest atlassian-rest-common 2.5.0   javax.xml.bind jaxb-api 2.2.4 provided  ...  ... 

并不总是需要明确地依赖于jaxb-api 。 例如, 上面的atlassian-rest-common插件对jaxb-api具有传递依赖性。 重要的是要了解范围的设置。 查看插件中的设置OSGi清单指令 (与插件,捆绑包和OSGi相同的页面但更进一步)。

这个好奇的人可以在OSGi Alliance Specifications和OSGi Community Wiki上了解更多信息 。

最后我找到了原因。

在JIRA(Felix)中加载插件时涉及许多ClassLoaders 。 它不会委托给’bootstrap’ClassLoader。 因此问题。

要知道哪个ClassLoader加载了JAXBContext类,请使用JAXBContext.class.getClassLoader()来打印一些Felix ClassLoader

它从jaxb-api.jar加载了类,而不是依赖于rt.jar但是它们实现了稍微不同的类。 rt.jar版本使用com.sun.xml.bind.internal.v2.ContextFactory ,其中jaxb-api版本使用com.sun.xml.bind.v2.ContextFactory

我能够使用JAXB的重叠方法来解决这个问题,它将另一个参数作为ClassLoader

花了很长时间。 但是,我对内心的细节和我的无知感到惊讶