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

时间:2010-06-22 14:13:59

标签: java command-line jaxb launch

我正在为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如何启动应用程序(因为我从命令行启动)。

3 个答案:

答案 0 :(得分:6)

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

第一个JIRA,或者更确切地说是Atlassian,有两种类型的插件,请参阅Differences between Plugins1 and Plugins2

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

从JIRA v4开始,JIRA充当OSGi容器,因此Plugin2是一个OSGi包。在OSGi中,每个bundle都有自己的一组类加载器。这使得不同的捆绑包具有相同罐的不同版本,并且可以进行热部署等。但问题是,并非JDK的所有软件包都默认可用于这些类加载器。这在Plugins, bundles and OSGiAtlassian Developers web page下进行了解释。可以在Springsource的博客Exposing the boot classpath in OSGi中找到更详细的描述。第二段甚至有标题 NoClassDefFoundError:com.sun ...

理论上这么多。

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

...
<build>
    <plugins>
        <plugin>
            <groupId>com.atlassian.maven.plugins</groupId>
            <artifactId>maven-jira-plugin</artifactId>
            <version>3.7.3</version>
            <extensions>true</extensions>
            <configuration>
                <productVersion>${jira.version}</productVersion>
                <productDataVersion>${jira.data.version}</productDataVersion>
                <systemProperties>
                    <property>
                        <name>atlassian.org.osgi.framework.bootdelegation</name>
                        <value>sun.*,com.sun.*</value>
                    </property>
                </systemProperties>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
        ...
    </plugins>
</build>
...

然后列出的包将可用于捆绑包。但请注意,启动委派不是解决所有问题的解决方案,只应与限制一起使用。在Boot DelegationAvoid Classloader Hacks了解详情。

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

...
<dependencies>
    <dependency>
        <groupId>com.atlassian.jira</groupId>
        <artifactId>atlassian-jira</artifactId>
        <version>${jira.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.atlassian.plugins.rest</groupId>
        <artifactId>atlassian-rest-common</artifactId>
        <version>2.5.0</version>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.4</version>
        <scope>provided</scope>
    </dependency>
    ...
</dependencies>
...

并不总是必须明确依赖 jaxb-api 。例如,上面的 atlassian-rest-common 插件对 jaxb-api 具有传递依赖性。 重要的是要了解范围的设置。查看Setting OSGi Manifest Instructions in your Plugin(与插件相同的页面,捆绑包和OSGi ,但是进一步向下)。

感兴趣的人可以在OSGi Alliance SpecificationsOSGi Community Wiki了解更多信息。

答案 1 :(得分:5)

最后我找到了原因。

在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。{/ p>

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

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

答案 2 :(得分:0)

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

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

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