If you’ve ever had issues with conflicting versions of the same jar file, you really need to take a look at JarJarLinks . JarJarLinks is an Ant task that lets you repackage jar files into your own package scheme by doing neato bytecode kungfu.

So you can do stuff like this to repackage commons-kungfu.jar into your own package structure:

        <jarjar jarfile="myapp.jar">
            <fileset dir="build/classes"/>
            <zipfileset src="lib/commons-kungfu.jar"/>
            <rule pattern="org.apache.commons.kungfu.**" result="au.com.bytecode.commons.kungfu.@1"/>
        </jarjar>

In the sample above (stolen from the manual), you simply use the jarjar task (which descends the standard jar task, and offers all the same config switches) to repackage the classes from commons-kungfu.jar into myapp.jar. Jarjar rips out the classes, changes the package naming to whatever makes sense for you, changes any references in your code to the new name, then adds the modded classes to your target jar. So, for instance, Jarjar does the work of changing all your references to org.apache.commons.kungfu to, say, au.com.bytecode.commons.kungfu and repackages the changed classes inside your own jar. You then no longer need to distribute commons-kungfu.jar with your app - the changed classes end up in your app’s jar file.

Here’s two killer scenarios…

  • Scenario one is when you don’t want to ship external jars (commons-kungfu.jar) with your standalone app.* Scenario two is when you want to bundle commons-kungfu.jar with your webapp, but your appserver has an old version of commons-kungfu.jar in its own root classloader. Use jarjar to package it into your own war file under a different package name and you’re good to go.

I’ve recently used it to great success where I wanted to deploy a particular jar file to /lib/ext on Websphere, but didn’t want to force everyone else on the appserver to use that particular version of the jar. Repackaged the jar into my own naming structure and I was good to go.

JarJar is even smart about embedded strings in your jar files. So if you do a Class.forName("org.apache.commons.kungfu.FactoryImpl") then that string will be successfully changed to the new package name too.

Many props to the guys at Tonic Systems. Really slick piece of work!