Steven has posted 36 posts at DZone. View Full User Profile

JarJar: solves class loading conflicts

01.26.2008
| 17444 views |
  • submit to reddit

Sometimes you're faced with a conflict between two versions of the same JAR in your classpath that cannot be resolved. Here's an example:

Weblogic uses Antlr (the Java compiler-compiler) for parsing EJB-QL queries. Hibernate 3 uses Antlr to parse HQL queries. The Weblogic kernel only sees its own Antlr version through its ClassLoader. Hibernate however sees Weblogic's version and its own. It cannot use Weblogic's version, however this is the one that will get loaded (it has priority in the ClassLoader hierarchy). More details on this issue can be found here.

Weblogic has an option to change the class loading priorities but this may cause other class loading issues like LinkageError. So is there no solution?

Enter JarJar, a lovely little Ant task that not only makes one jar out of many, it can also change package names of certain classes in byte-code! This effectively solved the titanic Weblogic/Hibernate clash we were facing.

Here's the Ant script we used to create a modified Hibernate JAR that also contains renamed Antlr classes:

<project name="jarjar-to-the-rescue">
    <property name="jarfile" value="hibernate-3.2.5.ga-jarjar.jar"/>
    <path id="classpath">
        <pathelement location="jarjar-1.0rc6.jar"/>
        <pathelement location="asm-2.2.3.jar"/>
    </path>
    <taskdef name="jarjar" 
            classname="com.tonicsystems.jarjar.JarJarTask" classpathref="classpath"/>
    <delete file="${jarfile}"/>
    <jarjar destfile="${jarfile}">
        <zipfileset src="hibernate-3.2.5.ga.jar"/>
        <zipfileset src="antlr-2.7.6.jar"/>
        <rule pattern="antlr.**" result="org.hibernate.jarjar.antlr.@1"/>
    </jarjar>
</project>

This script will create a new JAR file (hibernate-3.2.5.ga-jarjar.jar) that contains the contents of both Hibernate and Antlr jars. I will change the package name of all Antlr classes from antlr.* to org.hibernate.jarjar.antlr.*. It will also change this package in all Hibernate classes that depend on Antlr classes.

With this modified Hibernate JAR file there are still two Antlr versions on the class path. Since Hibernate no longer loads the antlr.* classes the conflict is effectively resolved. Example project and modified Hibernate JAR file attached.

Happy coding!

AttachmentSize
jarjar-example.zip2.51 MB
hibernate-3.2.5.ga-jarjar.jar2.59 MB
Published at DZone with permission of its author, Steven Devijver.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)