Automatic creation of Java archives
PrefaceCommand line versionEclipse plugin
Bernd Eggink, monoped@users.sourceforge.net Project page: SourceForge.net
Examples
Standard case
A program consists of the main class example.std.Std and several other classes residing in the directory classes. Additionally some classes from the archive libs/lib1.jar are used. The program loads the image file img1.png, using
getClass().getClassLoader().getResource("img1.png")
This file is located in the archive libs/imgs.jar. The manifest file std.mf contains a valid Main-Class entry. The output archive is std.jar. The command could then be:
java -jar autojar.jar -o std.jar -vc "classes:libs/lib1.jar" -p libs/imgs.jar \
    -m std.mf img1.png
Or alternatively:
java -jar autojar.jar -o std.jar -vc "classes:libs/*.jar" -b -m std.mf img1.png
Reflection
The classes of a program are located in the directory classes and in the archive my.jar. We know that the main class com.wow.MyApp dynamically loads a driver, but don't know its name. We suspect it is in drivers.jar, so we tentatively supply option -a along with this archive:
java -jar autojar.jar -av -o myapp.jar -c classes:my.jar:drivers.jar \
    com/wow/MyApp.class
If the output contains a line
* Dynamic loading: class com.wow.MyApp, method init, name="some.nice.Driver" (RESOLVED)
we know that the driver's name some.nice.Driver is a string constant, and Autojar has found and included the corresponding class.
If (RESOLVED) at the end of the line is missing, we know the name, but Autojar couldn't find the class via the class path. This means we first have to find out its location. If after some investigation we know that it is in the archive otherdrivers.jar, we simply add this to the class path:
java -jar autojar.jar -av -o myapp.jar -c classes:my.jar:drivers.jar:otherdrivers.jar \
    com/wow/MyApp.class

However, if the output looks like

* Dynamic loading, unknown classname:
    class com.wow.MyApp, method init
we are unlucky: Autojar couldn't find out the name of the class to be loaded. The last resort would then be to start the program anyway and wait for a ClassNotFound exception. The error message would reveal the name of the missing class, which could then be supplied as file parameter with the next Autojar run.
Manipulating archives
Three archives libA.jar, libB.jar, and libC.zip are to be combined into one, libSum.jar. Entries ending with .old, however, are to be skipped.
java -jar autojar.jar -o libSum.jar -- -X '*.old' libA.jar libB.jar libC.zip
If several source files contain an entry with the same name, only the first one will be copied. This can be used to "patch" a class library. Let's assume we have a huge open source library libX.jar in which we want to change a single class. We download the corresponding sources, edit a/b/X.java, and recompile this class:
javac -d classes -cp classes:libX.jar a/b/X.java
After this, we create a modified archive libX1.jar using the command
java -jar autojar.jar -o libX1.jar -c classes a.b.X.class libX.jar
Note the order of the last two parameters!
Auxiliary archives
You want to provide developers with a library libA.jar. The classes in this library depend on some classes from lib1.jar and lib2.jar. You want Autojar to etract these classes and combine them in an auxiliary library libAux.jar, which you will then supply in addition to libA.jar. The following command creates this library:
java -jar autojar.jar -o libAux.jar -c lib1.jar:lib2.jar -- -Y libA.jar
Without the prefix -Y libAux.jar would contain the complete content of libA.jar as well.
How Autojar creates itself
The archive autojar.jar has been created by applying Autojar to itself. The command in principle looks like this:
java -cp classes org.sourceforge.autojar.Autojar -av \
    -c classes:libs/bcel.jar:libs/log4j.jar -p log4j -o autojar.jar -m autojar.mf -- \
    -X .svn @src/classlist log4j.properties
Explanation: Autojar needs classes from the libraries bcel.jar and log4j.jar, and additionally the control file log4j.properties, which lies in the directory log4j. Being controlled by subversion, the project contains a lot of directories named .svn, which must not go into the output. Many classes from the package org.apache.bcel.generic are loaded dynamically, also two classes from log4j. To avoid an overly long command line, those class names have been written line by line into the file src/classlist.

An alternative which avoids the creation of src/classlist could look like this:

java -cp classes org.sourceforge.autojar.Autojar -av \
    -c classes:libs/bcel.jar:libs/log4j.jar -p log4j -o autojar.jar -m autojar.mf -- \
    -X .svn "org.apache.bcel.generic.*.class" org.apache.log4j.ConsoleAppender.class \
    org.apache.log4j.PatternLayout.class log4j.properties
In contrast to the above, all classes from the package org.apache.bcel.generic are copied, including some unnecessary ones, and the two log4j classes are supplied directly. The resulting jar file is about 20K bigger.
up
Created 2011-05-10 by mopcoge