|
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:
- The one-jar file
- main/main.jar
- 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.
|