Deliver Your Java Application in One-JAR™!

Copyright 2004-2010 by P. Simon Tuffs, All Rights Reserved. http://www.simontuffs.com




Resource Loading

There are a number of ways that Java supports finding and opening resources:
  • URL findResource(String resource): returns a resource, or null if not found.
  • Enumeration findResources(String resource): returns an enumeration of resource URL's which match the given string
  • URL.openConnection(): opens a connection to a resource by its URL.
One-Jar supports all of these mechanisms within the context of a One-Jar file, which may contain Jar files that have duplicate resources.

Resource Ordering

One-Jar defines a predictable order for classloading:
  1. The one-jar file
  2. main/main.jar
  3. lib/*.jar
Note: this assumes that the <one-jar> Ant task is used to construct the One-Jar. Otherwise, embedded Jar resources are loaded in the order they appear in the "jar -tvf" listing.

Duplicate Resources

Every Jar file has a required META-INF/MANIFEST file. With more than one Jar inside a One-Jar executable there will therefore be duplicates. Fortunately, this file is not a problem, since a normal Java application usually has many Jar files (or other codebases) on its classpath, meaning that it must use scanning to locate its own MANIFEST resources. One-Jar will have no impact in this situation.

An Example: Log4j

When multiple Jar files contain a resource with the same name, e.g. a log4j.properties configurator for the Log4J logging subsystem, there may be problems. Log4j is designed to process only the first log4j.properties file which it finds on the classpath, and ignores all others.

Consider a One-Jar which is composed of main.jar, library-a.jar, and library-b.jar. Suppose that each of these Jar files contains a log4j.properties file. Whichever Jar file initializes the Log4j subsystem by invoking Logger.getLogger(Class) will trigger the loading of log4j.properties. Which one will be chosen depends on the order that the JarClassLoader encountered them during the One-Jar bootstrap process. Fortunately this is well defined, the One-Jar order is: main/main.jar, lib/library-a.jar, lib/library-b.jar assuming that library-a.jar was ahead of library-b.jar in the Jar entry list (also the Ant <lib> list)

Consequently, to ensure proper initialization, just make sure that there is a log4j.properties file in the main/main.jar. Or, if main.jar is already assembled and you don't wish to rebuild it, simply put a log4j.properties file in the top-level One-Jar like so:

    <one-jar destfile="build/${test}-one-jar-log4j.jar">
        <file include="log4j.properties"/>
        <manifest>
    ... etc.
Since One-Jar delegates to the parent classloader which loads the One-Jar file, any top-level resources (or classes) will take precedence over those in the bundled Jar files.

If you like One-JAR then you might want to check out some of the other Open-Source projects developed by simontuffs.com:
Get One-JAR(TM) at SourceForge.net. Fast, secure and Free Open Source software downloads soap-stone at sourceforge.net Eclipse JAR Plugin Yet Another Compiler Compiler Language