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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3093963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:19:16  来源:igfitidea点击:

java class using jaxb api failing in jira with : Provider com.sun.xml.bind.v2.ContextFactory not found

javacommand-linejaxblaunch

提问by ernesto

I am writing a plugin for Jira which involves parsing of XML documents. I am using JAXB to do so (XML to pojos and vice versa) So have a class which generates XML from pojos using JAXB. it looks like...

我正在为 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();

  } 
}

The mentioned packages will come with JDK distribution (rt.jar). so i haven't relayed on anything else to run the class.

提到的包将随 JDK 发行版 (rt.jar) 一起提供。所以我没有传达任何其他内容来运行课程。

when i launch it from command line using 'java' it's working properly. but, when i package it as a jar and put it as plugin in Jira it's failing with the following error

当我使用“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)

This is on the same machine. only difference i could see is unlike launching from command line, when i deployed it in Jira, it's not calling the main() but m1() by instantiating.

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

I am wondering what is happening ! it's on the same machine. i do not know how Jira launches the application (as i am launching from command line).

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

采纳答案by skaffman

The com.sun.xml.bindpackage is part of the JAXB RI (http://jaxb.dev.java.net/), so you probably have that on your classpath somewhere.

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

Java6 has it's own version of JAXB included, in the com.sun.xml.internal.bindpackage, so you don't usually need the RI in Java6 .

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

The RI canmade made to work with Java6 , but it's uphill battle, and usually ends up with this sort of problem.

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

回答by peron

I know this is sort of a late answer, but for people landing here there are a few things not mentioned in the other posts that is of importance when developing plug-ins for JIRA (and other Atlassian products).

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

First JIRA, or rather Atlassian, has two types of plug-ins, see Differences between Plugins1 and Plugins2

首先 JIRA,或者说 Atlassian,有两种类型的插件,参见Plugins1 和 Plugins2 之间的差异

Since it was a ClassNotFoundException (and JIRA v4.0.1), I assume the plug-in is a Plugin2, which can be used in JIRA v4 and later.

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

From JIRA v4, JIRA acts as an OSGi container, and hence Plugin2 is an OSGi bundle. In OSGi every bundle has its own set of class loaders. This enables different bundles to have different versions of the same jars, and to be hot deployed, among other things. The catch, however, is that not all packages from the JDK is per default available to these class loaders. This is explained under Plugins, bundles and OSGion the Atlassian Developers web page. A more detailed description can be found in the blog Exposing the boot classpath in OSGiat Springsource. The second paragraph there even has the title NoClassDefFoundError: com.sun…

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

Such much for the theory.

这么多的理论。

When developing a plug-in for JIRA with the Atlassian SDK, Maven is used behind the scenes, see Atlassian Plugin SDK Documentation. So there will be a pom.xml in the plug-in project. To include JDK packages in the plug-in, one can add a <SystemProperties>tag to the maven-jira-plugin(for other Atlassian products, there's a corresponding maven plugin), and set the bootdelegationproperty (and you might want to set java to 1.6 for the maven-compiler-plugin):

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

...
<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>
...

The listed packages will then be available to the bundle. Be aware, though, boot delegation is not a fix it all solution, and should only be used with restriction. Read more at Boot Delegationand Avoid Classloader Hacks.

然后列出的包将可用于捆绑包。但是请注意,引导委派并不是解决所有问题的解决方案,只能在有限制的情况下使用。在引导委派避免类加载器黑客中了解更多信息。

Under the dependencies, one can set the jaxb-apiversion needed:

在依赖项下,可以设置所需的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>
...

It's not always necessary to explicitly have a dependency on jaxb-api. For example the atlassian-rest-commonplug-in above has a transitive dependency on jaxb-api. Important is to understand the setting of scope. Look at Setting OSGi Manifest Instructions in your Plugin(same page as Plugins, bundles and OSGibut further down).

并不总是需要显式依赖jaxb-api。例如,上面的 atlassian-rest-common插件具有对jaxb-api的传递依赖。重要的是了解scope的设置。查看在您的插件设置 OSGi 清单指令(与插件、捆绑包和 OSGi相同的页面但更进一步)。

The intrigued can learn more at OSGi Alliance Specificationsand OSGi Community Wiki.

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

回答by ernesto

Finally I was able find out the reason.

最后我找到了原因。

There are many ClassLoadersinvolved while loading the plugins in JIRA (Felix). which will not delegate to 'bootstrap' ClassLoader. And hence the problem.

ClassLoaders在 JIRA (Felix) 中加载插件时涉及很多。这不会委托给 'bootstrap' ClassLoader。这就是问题所在。

To know which ClassLoaderloaded the JAXBContextclass, use JAXBContext.class.getClassLoader()which will print some Felix ClassLoader.

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

It loaded the class from jaxb-api.jarinstead of relying on rt.jarbut they implemented the classes slightly different. rt.jarversion uses com.sun.xml.bind.internal.v2.ContextFactorywhere jaxb-apiversion uses com.sun.xml.bind.v2.ContextFactory.

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

I am able to solve the issue using overlaoded method of JAXB which will take another parameter as ClassLoader.

我能够使用 JAXB 的过载方法解决这个问题,该方法将另一个参数作为ClassLoader.

It took quite some time. But, I am surprised by the inner details & my ignorance

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