Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 979
ernesto Avatar asked Jun 22 '10 14:06

ernesto


1 Answers

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.

like image 75
peron Avatar answered Nov 15 '22 04:11

peron