Jabbering Giraffe

One-Jar

I was trying to fix the build of a project last night. It used to unpack several dependent jar files before repackaging them along with the project code. How ugly. Then I remembered about one-jar, which lets you package things in a slightly more sensible manner, retaining the individual files.

The documentation isn’t as good as it could be. But after a bit of poking around, I came up with this ant task to build my jar.

  <property name="onejar" value="one-jar-boot-0.95.jar"/>

    <target name="dist" depends="compile">
        <!-- Set up the on-jar directory structure. -->
        <mkdir dir="${build.onejar.dir}" />
        <mkdir dir="${build.onejar.dir}/boot" />
        <mkdir dir="${build.onejar.dir}/lib" />
        <mkdir dir="${build.onejar.dir}/main" />
        <!-- First, build just our code into a jar of its own. -->
        <jar destfile="${build.onejar.dir}/main/main.jar"
             basedir="${build.prod.dir}">
            <manifest>
                <attribute name="Main-Class"
                           value="net.happygiraffe.Main" />
            </manifest>
        </jar>
        <!-- Next, copy in the libs we depend upon. -->
        <copy todir="${build.onejar.dir}/lib">
            <fileset dir="${vendor.lib.dir}">
                <include name="*.jar" />
                <exclude name="${onejar}" />
            </fileset>
        </copy>
        <!-- Extract the One-Jar bits on top. -->
        <unjar src="${vendor.lib.dir}/${onejar}"
               dest="${build.onejar.dir}" />
        <!-- And finally, repackage. -->
        <jar destfile="${jar.path}"
             basedir="${build.onejar.dir}"
             manifest="${build.onejar.dir}/META-INF/MANIFEST.MF" />
    </target>

And then when I tried to run the jar, it fell over.

  Exception in thread "main" java.util.zip.ZipException: No such file or directory
          at java.util.zip.ZipFile.open(Native Method)
          at java.util.zip.ZipFile.<init>(ZipFile.java:203)
          at java.util.jar.JarFile.<init>(JarFile.java:132)
          at java.util.jar.JarFile.<init>(JarFile.java:70)
          at com.simontuffs.onejar.Boot.run(Boot.java:179)
          at com.simontuffs.onejar.Boot.main(Boot.java:105)

After substantial amounts of time messing around, it turned out that it’s a buug when you’re using Mac OS X and Java 5. The latest CVS code has a fix (Boot.java 1.14). Once I’d got the latest version from CVS, everything worked wonderfully. I only hope that it’s released soon.

Not only that, but when I looked through the CVS code, I noticed that there was an ant task as well. That would certainly simplify the rather verbose script above. I’ll have to look into that.

If you’re interested in the architecture of one-jar, check out the developerworks article Simplify your application delivery with One-JAR.