Lost in dependencies

My day had been completely wasted. So I decided that a blog post can’t make it any worse. Everything started when I typed gradlew deployServer Then I spent some semi-funny time.When this fun was over the server would not start anymore… An obscure NullPointerException was thrown somewhere deep in the core libs when the following code got executed JAXBContext.newInstance("somethig...");

The stack trace looked as ugly as this:

at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:132)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:286)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:244)

 

Please read carefully – javax.xml.bind.JAXBContext. But… this is part of the JDK! So now what? Stunned…. Google to the rescue? No, let’s make it more entertaining. The debugger is waiting there for me, why not enter under the hood of the JDK? Excellent opportunity! The problem was that I soon found out that the JDK sources mismatch the class that I was debugging. Blah! What is going on?

After a quick look at cartrides/lib I found this lib javax.xml.bind.jaxb-api-2.2.2.jar.  Nasty… Going back to google I discovered that there is a small bug and JAXB sometimes behaves really nasty (null pointers) when there are two conflicting reference implementations in the classpath. But how to find which caused the conflicting dependency?

The dependencies task in my assembly came to the rescue:

+--- com.sun.jersey:jersey-json:1.19
    |    +--- com.sun.xml.bind:jaxb-impl:2.2.3-1
    |    |    \--- javax.xml.bind:jaxb-api:2.2.2
    |    |         +--- javax.xml.stream:stax-api:1.0-2
    |    |         \--- javax.activation:activation:1.1

Oh, nooo – jersey is the culprit!!! Apparently the jaxb-api is a transitive dependency introduced by jersey. At this moment I almost felt desperate because we have a huge amount of infrastructure built upon the jersey client (which needs jersey JSON). We need jersey to continue! Our connector uses it to consume RESTful services. But why it needs JAXB reference implementation? I decided to browse a little bit the documentation of Jersey 1.19.

It says:

XML serialization support of Java types that are JAXB beans requires a dependency on the JAXB reference implementation version 2.x or higher.

Later:

Deploying an application for XML serialization support requires no additional dependencies, since Java SE 6 ships with JAXB 2.x support.

Here I’ve found more details about which JAXB RI is included in which Java SE.

Summary: it seems to me that the whole machinery is necessary so that the JSON serialization of JAXB annotated classes work with pre-Java 1.6 versions.
Which means that the dependency may be explicitly excluded from my build.

After a couple of chats I realized that with the current gradle version we can do that only on assembly level (because there is a little hack kindly provided in our gradle plugins). Here is what needs to be added:

configurations.all {
     exclude group: 'com.sun.xml.bind', module: 'jaxb-impl'
}

The server finally started smoothly. But I failed to login… Someone added a new column in the DB. Time for a DBInit…

Lost in dependencies
Tagged on: