Archive

Posts Tagged ‘maven’

Xerces and xml-api Dependency Hell

June 29th, 2011 3 comments

One of the project I work on includes a whole mish-mash of XML-related libraries including xerces, jdom, dom4j, jaxen, xalan. Some are direct dependencies and some are pulled in by other third-party dependencies like hibernate, tika, gate, etc. Many of these libraries have transitive dependencies on xerces and/or on some form of xml-api artifact, though the exact artifact name, and even the group name seem to vary randomly. What was xerces:xmlParserApis vs xml-apis:xml-apis vs xml-apis:xmlParserAPIs? Why were there versions of xml-api artifacts in the 2.0.x range, but they seemed older than version 1.0.b2 which so many libs depend on?

I recently tried to upgrade the included version of xerces from 2.6.2 to 2.9.1. This is the latest official release posted to Maven Central, though it is nearly 4 years old. (The latest official xerces release, 2.11.0, and the previous one, 2.10.0, are not in the primary maven repos. See XERCESJ-1454 if interested in more on why.) The upgrade caused some rather strange class loader errors that forced me to finally dig into this. What follows are my rough notes on the various xml-api related artifacts. They go in chronological order.

Group IDArtifact IDVersionRelease DateNotes
xerces
xml-apis
xmlParserApis
xmlParserApis
2.0.0
2.0.0
01/30/2002
xerces
xml-apis
xmlParserApis
xmlParserApis
2.0.2
2.0.2
06/21/2002
xercesxmlParserApis2.2.111/11/2002includes all classes in 2.0.2, plus some security support stuff and other mods
xml-apisxml-apis1.0.b2
2.0.0
2.0.2
12/01/2002includes all but some security support and other util class in xerces:xmlParserApis:2.2.1, plus some additions
xercesxmlParserApis2.6.0
2.6.0
2.6.2
11/18/2003* all but 1 class from xml-apis:1.0.b2, plus the security support classes that were in xerces:xmlParserApis:2.2.1
* 2.6.2 was the last of this artifact
xml-apisxml-apis1.2.01* no jar, just a relocation tag to xerces:xmlParserApis:2.6.2
* Looks like this was added on 02/03/2010 (judging by date in http://repo1.maven.org/maven2/xml-apis/xml-apis/), about 3 years after other xml-apis:xml-apis entries like 1.3.04
xml-apisxml-apis1.3.0207/22/2005* includes all but 1 class from v2.6.2 (dropped older security support stuff), plus many additions
* Included with xerces 2.7.1
xml-apisxml-apis1.3.0302/25/2006* released with xerces 2.8.0
* xercesImpl:2.8.0 was the first one where they included dependency info in the pom
xml-apisxml-apis1.3.0411/19/2006* xerces:xercesImpl:2.9.1 (09/14/2007) depends on this
* this is the last of this artifact in maven repos

One interesting note is that xml-apis:xml-apis:2.0.0 and 2.0.2 are newer than their equivalent versions of xerces:xmlParserApis and xml-apis:xmlParserAPIs.

While tedious, working out these relationships helped me track down the conflicting dependencies.  I added these entries to my root project’s dependencyManagement section:

<dependency>
    <groupId>xml-apis</groupId>
    <artifactId>xml-apis</artifactId>
    <version>1.3.04</version>
</dependency>
<dependency>
  <groupId>jaxen</groupId>
  <artifactId>jaxen</artifactId>
  <version>1.1.1</version>
    <exclusions>
        <exclusion>
            <groupId>xerces</groupId>
            <artifactId>xmlParserAPIs</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
  <groupId>jmimemagic</groupId>
  <artifactId>jmimemagic</artifactId>
  <version>0.1.2</version>
    <exclusions>
        <exclusion>
            <groupId>xml-apis</groupId>
            <artifactId>xmlParserAPIs</artifactId>
        </exclusion>
    </exclusions>
</dependency>

and all was good in the world again.

Categories: maven, XML Tags: , ,

Running latest Groovy from Maven

April 5th, 2011 2 comments

Say you have a groovy-project that you build with maven.  You use the org.codehaus.gmaven:gmaven-plugin to compile your groovy code and run groovy tests without a problem.  Then you add some features or tests that need groovy 1.7.  You add the proper dependency and version to the <dependencies> section of your pom, run your test… and watch it blow up because the gmaven-plugin defaults to using groovy 1.6.  So you dig around on the web and find references for how to use the <providerSelection> tag of the gmaven-plugin to get your code compiled with 1.7 and to use 1.7 when running tests.  Things seem good.  Until…

You add a feature that requires some version of groovy greater than 1.7.4 (the version included with the latest gmaven-plugin, 1.3).  In my case, I used the @Delegate annotation with some inheritance in a test configuration and hit a bug that was fixed in groovy 1.7.6.  No matter what version I used in my dependencies section, my tests were executed under groovy 1.7.4.  I finally came up with the configuration below which let me run with a different groovy.  Note that it made no difference what I included in the dependencies section.  The gmaven-plugin configuration appears to be completely independent of that.

<plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <configuration>
        <providerSelection>1.7</providerSelection>
        <!-- This is only used if you want to run a groovy script from the command line using maven -->
        <source>${groovy.script}</source>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
                <goal>testCompile</goal>
            </goals>
        </execution>
    </executions>
    <!-- This block is required in order to make the gmaven plugins use a groovy other than 1.7.4.
     This is independent of the groovy entry in the dependencies section.  This does not affect the class path.

     What is interesting is that there must be both the gmaven.runtime entry with the explicit excludes
     and the additional dependency on whatever version we do want to use.  If you exclude the former,
     it will throw an exception. -->
    <dependencies>
        <dependency>
            <groupId>org.codehaus.gmaven.runtime</groupId>
            <artifactId>gmaven-runtime-1.7</artifactId>
            <version>1.3</version>
            <exclusions>
                 <exclusion>
                     <groupId>org.codehaus.groovy</groupId>
                     <artifactId>groovy-all</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>1.7.6</version>
        </dependency>
    </dependencies>
</plugin>

Grails, Maven, packaging, and skipTests fun

April 22nd, 2010 No comments

The grails maven plugin honors the maven.test.skip option (which turns off compiling and executing tests), but not the skipTests option (which only turns off executing tests). This means that you cannot easily create a package with test classes in it without running all of the tests. I finally come up with a close work around:

mvn clean grails:exec install -Dcommand=test-app -Dargs="-unit DoesNotExist" -Dmaven.test.skip=true

By explicitly listing the test-app command but specifying a test that does not exist, I was able to get the unit tests to be compiled. Since I only needed some common testing files in my package, this works for me. If someone wanted to package both the unit and integration tests, I don’t think this would work. I filed a new issue in the Grails Jira to try to get a real resolution.

Grails+Maven+GeoTools+PdfBox = PITA

March 20th, 2010 No comments

Here’s a bit of maven-voodoo for you. If you have a Grails (1.1.1) app that is built with Maven (2.1) and you try to link in GeoTools (specifically the gt-xsd-core module) and you try to bring in PdfBox as well, you will get really fascinating class loading and linking problems revolving around various XML pieces. I finally found two different ways to get rid of the errors. For those who like to cut to the chase, I’ll list the solutions first and then explain a bit more what errors I was seeing.

Solution #1: Exclude, exclude, exclude

If you don’t need commons-jxpath, you can add these three exclusions to the gt-xsd-core dependency declaration.

    <dependency>
        <groupId>org.geotools.xsd</groupId>
        <artifactId>gt-xsd-core</artifactId>
        <version>${gt.version}</version>
        <exclusions>
            <exclusion>
                <groupId>commons-jxpath</groupId>
                <artifactId>commons-jxpath</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis-xerces</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

This at least works for me given the subset of geotools functionality I am using (primarily encoding and parsing OGC Filter objects to and from XML so I can persist them with Hibernate). It is still pulling in xercesImpl and that appears to be enough, at least to get my unit and integration tests working.

Solution #2: Using Dependency Management

If you need the commons-jxpath functionality in gt-xsd-core, add this to your dependencyManagement section of your POM:

    <dependencyManagement>
        <dependencies>
            <!-- The gt-xsd-core tries to bring commons-jxpath 1.2 in.  That messes up the maven junitreport plugin for
            some reason (like links to a version of xalan or xml-apis or something.  The 1.3 version doesn't have that
            issue. -->
            <dependency>
                <groupId>commons-jxpath</groupId>
                <artifactId>commons-jxpath</artifactId>
                <version>1.3</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

and then keep the exclusions for the xml-api artifacts as above:

    <dependency>
        <groupId>org.geotools.xsd</groupId>
        <artifactId>gt-xsd-core</artifactId>
        <version>${gt.version}</version>
        <exclusions>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis-xerces</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

This is what I have setup in my POM right now because I think I might need jxpath soon. I also tried adding a node in dependency management to use the 1.3.03 version of xml-apis rather than 1.0b2 (which is what was pulled in by default), but that doesn’t appear to make any difference. I still had to have the 2 exclusions under gt-xsd-core for things to work.

So what was the problem?

Now, a little more about the problems I had. I had two types of errors:

Maven junitreport conflict – When I added the dependency for gt-xsd-core and then ran my unit tests using the maven grails plugin (mvn grails:exec -Dcommand=test-app -Dargs="-unit"), my tests would run fine (except for one which I’ll detail below), but then I would get this error when the junitreport plugin tried to run its XSL transform:

Embedded error: java.lang.reflect.InvocationTargetException
Provider org.apache.xalan.processor.TransformerFactoryImpl not found

Normally I would suspect that the geotools dependencies brought in some new version of the xalan library and it didn’t have an old class that the junitreport plugin required. To check this, I compared the output from both maven dependency:classpath and dependency:tree between my trunk branch and the branch where I had added the geotools dependencies. The comparision showed that only one one dependency had changed between the branches; a newer version of commons-pool was used. All other classpath mods were new libraries that were not previously included at all. In fact, xerces and xalan was not included by the trunk branch at all. I am sure that someone with more recent experiences with xml-apis, xerces, and xalan knows exactly what was happening. My guess is that by including the xml-apis-xerces dependency, some piece of the junitreport plugin thought that it could use xalan as opposed to some other XSL lib that it would use when xerces was not present. This is supported by the fact that if I added xalan as a dependency, the error went away. If I have time, I’ll look at the docs for junitreport one of these days and see if that sheds some light on the issue.

PDFImageWriter/NodeList conflict – One of the unit tests exercised our use of PDFBox. If I did not have the above exclusions and I include xalan, this error appeared during the PDFImageWriter constructor:

java.lang.LinkageError: loader constraint violation: loader (instance
of <bootloader>) previously initiated loading for a different type with
name "org/w3c/dom/NodeList"

I haven’t tracked down exactly why this linkage conflict occurred. The bizare thing is that I inserted some link-loading debugging that I used in the past to try to see where NodeList was coming from in both my trunk and geotools-enabled branches:

def clazz = org.w3c.dom.NodeList.class
def codeSource = clazz.getProtectionDomain().getCodeSource();
println ("Source Location: " + codeSource);

In trunk (i.e. no geotools and working fine), it came back as null; NodeList wasn’t loaded at all. In the geotools-enabled branch, it would load (from xerces, I think), but then had that conflict.

At this point, I have a solution (two, actually) and have spend pretty much a whole day researching various paths, so I need to wrap it up and move on. If anyone has a better solution or thoughts as to why exactly there were problems, feel free to comment.

One last note in case there is any confusion from me mentioning xalan so much – I did not end up adding a dependency for xalan to my POM. Just using the exclusion statements listed above solved the issue.