mercredi 29 avril 2015

Maven shade plugin + JAXB RI

I have encountered the following problem while trying to use maven shade plugin with the code that uses JAXB.

I would like to pack my code into uber-jar with all dependencies shaded, so I include the following into pom.xml:

<relocations>
<relocation>
<pattern>com</pattern>
  <shadedPattern>quase.com</shadedPattern>
</relocation>
<!-- ... other top-level patterns for external dependencies -->
<relocation>
  <pattern>org</pattern>
  <shadedPattern>quase.org</shadedPattern>
  <excludes>
    <exclude>org.aau.**</exclude> <!-- my own code is not shaded -->
  </excludes>
</relocation>
</relocations>

The problem is that my code uses JAXB (default rt.jar implementation), so after calling the initialization:

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://ift.tt/Qb9Hvl", false);

JAXBContext jaxbContext = JAXBContext.newInstance(ADOXML.class);
ADOXML adoxml = (ADOXML) jaxbContext.createUnmarshaller().unmarshal(
    new SAXSource(spf.newSAXParser().getXMLReader(),
        new InputSource(String.valueOf(new File(fileName).toURI()))));

I got the following error:

[java.lang.ClassNotFoundException: quase.com.sun.xml.internal.bind.v2.ContextFactory]
        at quase.javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:241)
        at quase.javax.xml.bind.ContextFinder.find(ContextFinder.java:455)
        at quase.javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:652)
        at quase.javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:599)
        at quase.org.aau.quase.quontology.builder.QuBuilderUtils.getModelFromFile(QuBuilderUtils.java:185)
        at quase.org.aau.quase.quontology.ontology.QuOntologyOWLAPI.createOntologyFromModel(QuOntologyOWLAPI.java:574)
        at org.aau.quase.quontology.builder.QuSiteOntologyBuilder.main(QuSiteOntologyBuilder.java:43)
Caused by: java.lang.ClassNotFoundException: quase.com.sun.xml.internal.bind.v2.ContextFactory
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at quase.javax.xml.bind.ContextFinder.safeLoadClass(ContextFinder.java:573)
        at quase.javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:239)
        ... 6 more

It seems that the rt.jar implementation of JAXB (which includes com.sun.xml.internal.bind.v2.ContextFactory) is not getting shaded with the rest of the dependencies because it is not available to me separately - only as a part of rt.jar so it is not included into uber-jar. But the code which calls it got modified and expects the shaded version i.e. quase.com.sun.xml.internal.bind.v2.ContextFactory.

I tried to do two things to resolve this issue:

  1. I have tried to explicitly un-shade the offending class:

    <relocation>
    <pattern>com</pattern>
    <shadedPattern>quase.com</shadedPattern>
    <excludes>
        <exclude>com.sun.xml.internal.bind.v2.**</exclude>
    </excludes>
    </relocation>
    
    

    but this seemed to have little effect, as now I got an error in this form

    [java.lang.ClassNotFoundException: quase/com.sun.xml.internal.bind.v2.ContextFactory]
            at quase.javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:241)
     ... 
    
    

    so now instead of missing the class in a shaded package i.e. quase.com.sun... it misses the class in a kind of directory i.e. quase/com.sun... This seems to be a problem with the reflection handling in the shade plugin, as the reflection-based calls got modified to expect shaded versions regardless of excluding the classes being called from shading.

  2. I have tried to grab the complete control over JAXB version I am using by putting the non-rt.jar versions of JAXB (jaxb-api-2.2.11.jar and jaxb-impl-2.2.11.jar) into "endorsed" directory and making maven know about it:

    <compilerArguments>
    <endorseddirs>c:/java/jdk1.8.0_31/lib/endorsed</endorseddirs>
    </compilerArguments>
    
    

    but this still has no effect for some reason - the error is the same as above so the code still expects the rt.jar version of the JAXB code to be called (as non-rt versions of JAXB do not include com.sun.xml.internal.bind but instead com.sun.xml.bind).

What am I doing wrong? Any suggestions?





Aucun commentaire:

Enregistrer un commentaire