【问题标题】:java class using jaxb api failing in jira with : Provider com.sun.xml.bind.v2.ContextFactory not found使用 jaxb api 的 java 类在 jira 中失败:Provider com.sun.xml.bind.v2.ContextFactory not found
【发布时间】:2014-02-20 14:44:24
【问题描述】:

我正在为 Jira 编写一个涉及 XML 文档解析的插件。我正在使用 JAXB 这样做(XML 到 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 是如何启动应用程序的(因为我是从命令行启动的)。

【问题讨论】:

标签: java command-line jaxb launch


【解决方案1】:

我知道这是一个迟到的答案,但对于登陆这里的人来说,在为 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 可以拥有相同 jar 的不同版本,并且可以进行热部署等。然而,问题是并非所有来自 JDK 的包都默认可供这些类加载器使用。这在Atlassian Developers web pagePlugins, bundles and OSGi 下进行了解释。更详细的描述可以在 Springsource 的博客 Exposing the boot classpath in OSGi 中找到。那里的第二段甚至还有标题 NoClassDefFoundError: com.sun…

理论讲了这么多。

使用 Atlassian SDK 为 JIRA 开发插件时,会在后台使用 Maven,请参阅 Atlassian Plugin SDK Documentation。所以插件项目中会有一个pom.xml。要在插件中包含 JDK 包,可以在 ma​​ven-jira-plugin 中添加 <SystemProperties> 标签(对于其他 Atlassian 产品,有相应的 maven 插件),并设置 bootdelegation 属性(您可能希望将 ma​​ven-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了解更多信息。

【讨论】:

    【解决方案2】:

    终于找到原因了。

    在 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 的 overlaoded 方法解决问题,该方法将采用另一个参数作为 ClassLoader

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

    【讨论】:

    • jaxb-api.jar 是我之前建议的 JAXB RI 的一部分,实现包名称也是如此。
    • ernesto,您如何/什么重载以指定不同的引导加载程序。我正在尝试使用 jython 编组和解组并得到相反的错误。找到 com.sun.xml.bind.v2.ContextFactory 但找不到 com.sun.xml.internal.bind.v2.ContextFactory。从 jython JAXBContext.getClassLoader() 方法返回 org.python.core.SyspathJavaLoader
    【解决方案3】:

    com.sun.xml.bind 包是 JAXB RI (http://jaxb.dev.java.net/) 的一部分,因此您的类路径中可能有它。

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

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

    【讨论】:

    • 不。我已经清除了我的 CLASSPATH。到目前为止,我明白,发生了什么,因为我正在使用位于 rt.jar 中的 'javax.xml.bind.*' (可能这些类在内部使用 com.sun.xml.internal.bind.* )。当我通过 CL 运行我的程序时,“引导类加载器”正在加载所需的类,因此程序运行顺利。当我在 Jira(tomcat) 中部署它时,其他一些“ClassLoader”正在尝试加载类并导致问题
    • 希望我很清楚。这是链接developer.com/java/other/article.php/10936_2248831_2/… 我真的需要一些帮助我不知道发生了什么。
    猜你喜欢
    • 2015-06-11
    • 2022-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-24
    • 2016-03-13
    • 2018-10-27
    相关资源
    最近更新 更多