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

最后都变了- 提交于 2020-01-09 11:18:34

问题


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

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.

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

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.

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


回答1:


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

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

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




回答2:


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

First JIRA, or rather Atlassian, has two types of plug-ins, see Differences between Plugins1 and 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.

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 OSGi on the Atlassian Developers web page. A more detailed description can be found in the blog Exposing the boot classpath in OSGi at Springsource. The second paragraph there even has the title 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 bootdelegation property (and you might want to set java to 1.6 for the 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 Delegation and Avoid Classloader Hacks.

Under the dependencies, one can set the jaxb-api version needed:

...
<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-common plug-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 OSGi but further down).

The intrigued can learn more at OSGi Alliance Specifications and OSGi Community Wiki.




回答3:


Finally I was able find out the reason.

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

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

It loaded the class from jaxb-api.jar instead of relying on rt.jar but they implemented the classes slightly different. rt.jar version uses com.sun.xml.bind.internal.v2.ContextFactory where jaxb-api version uses 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.

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



来源:https://stackoverflow.com/questions/3093963/java-class-using-jaxb-api-failing-in-jira-with-provider-com-sun-xml-bind-v2-co

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!