Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JarJar: solves class loading conflicts

DZone's Guide to

JarJar: solves class loading conflicts

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

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!

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}