Simplify Your Application Delivery with One-JAR
By P. Simon Tuffs2005-04-22
Problems and solutions
• Load classes/resources that appear at the root of a JAR file.
• Load classes/resources that are in codebases pointed to by the META-INF/MANIFEST.MF Class-Path attribute.
Moreover, it deliberately ignores any environment variable settings for CLASSPATH or the command-line argument -cp that you supply. And it does not know how to load classes or resources from a JAR file that is contained inside another JAR file.
Clearly, I would need to get around this to meet my goals for One-JAR.
Solution 1: Expand supporting JAR files
My first attempt at creating a single executable JAR file was to do the obvious and expand the supporting JAR files inside the deliverable JAR file, which we'll call main.jar. Given an application class called com.main.Main, and assuming it depends on two classes -- com.a.A (inside a.jar) and com.b.B (inside b.jar) -- the One-JAR file would look like this:
main.jarThe fact that A.class originally came from a.jar has been lost, as has the original location of B.class. While this may appear to be a minor point, it can cause real problems, as I'll explain in a moment.
| com/main/Main.class
| com/a/A.class
| com/b/B.class
Expanding the supporting JAR files to the filesystem to create a flat structure can be quite time-consuming. It also requires working with build tools like Ant to expand and re-archive the supporting classes.
Aside from this minor annoyance, I quickly encountered two serious problems with expanding the supporting JAR files:
• If a.jar and b.jar contain a resource with the same pathname (say, log4j.properties ) which one do you pick?
• What do you do if the license for b.jar expressly requires you to redistribute it in an unmodified form. You can't expand it like this without violating the terms of that license.
I felt that these limitations warranted another approach.
One-JAR and FJEP
A recently-released tool called FJEP (FatJar Eclipse Plugin) supports the building of flattened JAR files directly inside Eclipse. One-JAR has been integrated with FatJar to support the embedding of JAR files without expanding them. See Resources to learn more about it.
Solution 2: The MANIFEST Class-Path
I decided to investigate a mechanism in the java -jar loader that will load classes which are specified inside a special file in the archive named META-INF/MANIFEST.MF. By specifying a property called Class-Path I hoped to be able to add other archives to the bootstrap classloader. Here is what such a One-JAR file would look like:
main.jarDid this work? Well it appeared to until I moved the main.jar file somewhere else and tried to run it. In order to assemble main.jar I had created a subdirectory named lib and pushed a.jar and b.jar down into it. Unfortunately, the application classloader was simply picking up the supporting JAR files from the file-system. It wasn't loading classes from the embedded JAR files.
| META-INF/MANIFEST.MF
| + Class-Path: lib/a.jar lib/b.jar
| com/main/Main.class
| lib/a.jar
| lib/b.jar
To get around this, I tried using Class-Path with several variations on the rather arcane jar:!/ syntax (see "A note and a clue"), but I couldn't get anything to work. What I could do was deliver a.jar and b.jar separately and scatter them into the filesystem alongside main.jar; but that was exactly the kind of thing I wanted to avoid.
A note and a clue
URLClassloader is a base class of sun.misc.Launcher$AppClassLoader that supports a rather arcane URL syntax that lets you refer to resources inside a JAR file. The syntax works like so: jar:file:/fullpath/main.jar!/a.resource.
In theory, to get to an entry inside a JAR file inside a JAR file you would have to use something like jar:file:/fullpath/main.jar!/lib/a.jar!/a.resource, but unfortunately this doesn't work. The JAR file protocol handler treats only the last "!/" separator as indicating a JAR file.
But this syntax does hold a clue to my final One-JAR solution ...
Tutorial pages:
|
First published by IBM DeveloperWorks
|
|||||||||
You might also want to check these out:
|
Leave a Comment on "Simplify Your Application Delivery with One-JAR"
You must be logged in to post a comment.
Link to This Tutorial Page!

