Jun
6
2006

Doing Package Name Kung-Fu with JarJarLinks

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!

About the Author: Glen Smith

3 Comments + Add Comment

  • Hello
    About the second scenario : you can also force the classloader to load the version of common-kungfu shipped in the webapp. In the websphere admin console, you need to set the property “classloader preference” to “PARENT_LAST” (default value is “PARENT_FIRST”).
    Hope it helps

  • Great point, Victor! You’d need to do it for every webapp running on that server I’d assume. Or is there a way to change that setting globally? So all webapps default to PARENT_LAST (including newly deployed ones)?

  • I am not sure you can change the default settings… However, you can use jacl scripts to automatically deploy your war and set up the classloaders.

    Alex

Leave a comment

Glen Smith

About Glen

Co-author Grails in Action