Autojar - create jar archives automatically

By Bernd Eggink, Regionales Rechenzentrum der Universität Hamburg
e-mail: monoped@users.sourceforge.net
deutsch German version
SourceForge project page

  1. Purpose
  2. Download
  3. History
  4. Usage
  5. Options
  6. File parameters
  7. Dynamic class loading
  8. Examples
  9. Compiling it yourself
  10. Bugs

1. Purpose

Autojar helps creating jar files of minimal size from different inputs like own classes, external archives etc. It starts from one or more given classes (e.g., an applet), recursively searches the bytecode for references to other classes, extracts these classes from the input archives, and copies them to the output. The resulting archive will only contain the classes you really need. Thus you can keep size and loading time of applets low or make applications independent of installed libraries.
In a similar way, autojar can search directories and archives for other resources (like image files), extract them and copy them to the output.

Note that autojar in principle can't know which classes will be loaded dynamically (by Class.forName()). However, starting from version 1.3, one can tell autojar to search the bytecode for invocations of Class.forName() and inform you correspondingly. In some cases autojar actually can find out which classes are to be loaded, and add them automatically to the output (see 7.).

Autojar uses the excellent bcel package (http://jakarta.apache.org/bcel/).

Note: In the following examples, file- and classpaths are mostly written in linux notation. Windows users will have to replace file paths correspondingly and replace colons by semicolons in classpaths.

2. Download

Download via the SourceForge project page .
An rpm package is available at http://www.jpackage.org

3. History

Version 1.3.1: Minor bug fixes.
With option -v, autojar now outputs a list of archives that are included in the classpath, but never used.
New option -X allows exclusion of file and folder names.

Version 1.3: Project moved to SourceForge.
Some bugs fixed. Non-class files are now handled correctly even if their names contains more than one dot.
Dynamic loading is detected. Options -d and -a added.
Any command line parameter may be of the form @file, not just the first.

Version 1.2.2: Some bugs fixed.
New options: -e, -q, -D.
Wildcards ? and * allowed in search paths.
Improved dependency checking.
Missing files are reported.

Version 1.1: Along with option -p, a search path for non-class files may be supplied (e.g., .gif files). Alternatively option -b ("both") tells autojar to search the class path for non-class files as well.

4. Usage

Autojar comes in two flavours with equal functionality. The file autojar.jar is th self-contained version, created by autojar itself. Use it if you don't have BCEL installed. It is started by the command
autojar [option...] [file...]
The second version, autojar-core.jar, is much smaller, as it contains only the autojar classes. You must have bcel-5.1.jar (or better) in your classpath to use it. Start it like this:
java -cp autojar-core.jar:bcel.jar de.uni_hamburg.eggink.autojar.Autojar [option...] [file...]
(As usual, Windows users have to use semicolon instead of colon in the classpath). Any program parameter (options and files) may be supplied directly on the command line or read from a text file. Example:
autojar -o old.jar @params -c in.jar @class-list
Each line in params and class-list is considered a program parameter and inserted into the command line sequence.

5. Options

Option Meaning
-b Use classpath for non-class files.
-c classpath Class path in the usual format (system dependent), used to search for class files. Default is ".". The name part of each component may contain wildcards * and ?.

Example (Linux): Directory /foo contains the archives a.jar, b.jar, c.jar. The expression -c "/ah/oh:/foo/*.jar" then expands to

    -c /ah/oh:/foo/a.jar:/foo/b.jar:/foo/c.jar
The argument must be quoted to prevent expansion of the wildcards by the shell.

Example (Windows): Directory C:\foo contains the archives a.jar, b.jar, c.jar. The expression -c C:\ah\oh;C:\foo\*.jar expands to

    -c C:\ah\oh;C:\foo\a.jar;C:\foo\b.jar;C:\foo\c.jar
Multiple instances are merged into one: -c /usr/foo -c /usr/bar is the same as -c /usr/foo:/usr/bar.
-d Autojar searches the bytecode for invocations of Class.forName("name") and prints corresponding messages (see 7.).
-a For each invocation of the kind Class.forName("name") in the bytecode, autojar tries to find and add the class name. Implies -d.
-D Debug mode, shows more detailed error output (stack trace). Not normally used.
-e Search all jars in all Java extension directories (system property "java.ext.dirs"). Without this option, archives in $JAVA_HOME/jre/lib/ext that are to be searched must be specified explicitely.
-h Print help and exit.
-m manifest Path of the manifest file. The class in the Main-Class entry will be treated like classes given on the command line.
-o outfile Output file, mandatory.
-p searchpath Search path for non-class files, same format as class path.
-q Run silently. Don't issue warnings.
-v Verbose output.
-x prefix Exclude prefix. Directories and archives in the search path whose path names start with prefix are ignored. Multiple instances are allowed.
-- End of options. All remaining parameters are regarded non-options, even if starting with - .

6. File parameters

An arbitrary number of file or directory paths may be supplied. What happens depends on the file type:

Note that -C and -X are not options. If one of these is the first non-option parameter, it must be prefixed by -- to tell autojar it is not an option.

Classes from the Java runtime library will never be included in the output.

At exit, if Option -q is not present, autojar prints a list of missing files.

7. Dynamic class loading

Since version 1.3, if option -d is supplied, autojar searches the bytecode for invocations of Class.forName(name). A message is printed for each invocation found. If name is a constant (string literal), autojar already knows the class; the message will then read
* Dynamic loading: class Test, method g, name="Blah"
If option -a is present (implies -d), autojar tries to handle this class like a statically loaded class - that is, find it via the classpath and add it to the output file. It it succeeds, the message will read
* Dynamic loading: class Test, method g, name="Blah" (RESOLVED)
However, if name is not a literal, but a normal string reference, autojar can't know the class in advance. Messages about such invocations are printed separately:
* Dynamic loading, unknown classname:
    class Test, method f
    class Foo, method bar
In this case the output archive may be not self-containded, and using it may result in ClassNotFound exceptions. Of course this will only happen if the calls to Class.forName() actually get executed. One has to find that out experimentally.

Invocations of Class.forName() in compiler generated methods are ignored (see, however, Bugs).

8. Examples

Example 1: An applet consists of a main class MyApplet plus several other classes, all in the directory classes. Additionally some classes from the archive /local/lib/foo.jar are used, and all image files in the directory images, which are referred to as "x.gif", "y.gif" etc. (that is, without the directory part). The jar file may then be created like this:
autojar -vc classes:/local/lib/foo.jar -o myapplet.jar MyApplet.class -C images '*.gif'
If you refer to your image file as "images/x.gif", "images/y.gif", replace -C images '*.gif' by 'images/*.gif'.

Example 2: An application consists of a main class Magic and 199 additional classes, mixed up with classes from other projects, sources, and all kinds of junk in your working directory (not a particularly good idea, of course). The file magic.mf contains the entry Main-Class: Magic. Now the call

autojar -o magic.jar -m magic.mf

creates the archive magic.jar, saving you from the need to supply all 200+ names individually.

Example 3: An application with main class com.wow.MyApp dynamically loads a driver. You have no idea which class that is, but you suspect it might be contained in the archive drivers.jar. So you try option -a and include the archive in the classpath:

autojar -av -o myapp.jar -c my.jar:drivers.jar classes/com/wow/MyApp.class
If you are lucky, you get an output like
* Dynamic loading: class com.wow.MyApp, method init, name="some.nice.Driver" (RESOLVED)
This means that autojar found out the name of the driver and added the class to the archive.

If you are less lucky, the word RESOLVED is missing, which means you now know the name of class, but not where the its file is. This you have to find out yourself. If it'a plain file, symply add it to the command line; if it's in a jar file, add this to autojar's class path.

However, if the first message sounds like

Dynamic loading, unknown classname:
    class com.wow.MyApp, method init
you have bad luck: Autojar couldn't find out the name of the class. The last resort is to start the program anyway and wait for ClassNotFound exceptions. If they happem, you know which classes are missing. Run autojar again and supply them on the command line this time.

Example 4: An Applet creates several graphical buttons. It needs all files from the directory images, and the two icons toolbarButtonGraphics/general/Cut16.gif and toolbarButtonGraphics/general/Paste16.gif from Sun's archive /usr/local/jlfgr-1_0.jar. The applet loads all images from its own archive:

JButton cutButton = new JButton(new ImageIcon(getClass().getResource("toolbarButtonGraphics/general/Cut16.gif"))),
        pasteButton = new JButton(new ImageIcon(getClass().getResource("toolbarButtonGraphics/general/Paste16.gif"))),
        someButton =  new JButton(new ImageIcon(getClass().getResource("images/some.png"))),
        /* ... */
The directory images is controlled by subversion and thus contains a subdirectory .svn, which should not go into the jar file. So the command could be:
autojar -o myapplet.jar -p /usr/local/jlfgr-1_0.jar MyApplet.class \
    toolbarButtonGraphics/general/Cut16.gif toolbarButtonGraphics/general/Paste16.gif -X .svn images
If you need all images from the Sun archive or don't care about size, you could also write
autojar -o myapplet.jar /usr/local/jlfgr-1_0.jar MyApplet.class -X .svn images
This would include the whole content of jlfgr-1_0.jar in your archive.

9. Compiling it yourself

If you want to compile autojar yourself, get the bcel package and include bcel.jar in the classpath. Example:
javac -d classes -cp classes:bcel.jar -sourcepath . de/uni_hamburg/eggink/autojar/Autojar.java
You may then run it like this:
java -cp classes:bcel.jar de.uni_hamburg.eggink.autojar.Autojar parameters...
Optionally you can build a self-contained version by applying autojar to itself:
java -cp classes:bcel.jar de.uni_hamburg.eggink.autojar.Autojar -vac bcel.jar:classes \
    -m autojar.mf -o autojar.jar de.uni_hamburg.eggink.autojar.Autojar.class @classlist
The files autojar.mf and classlist are included in the directory src of the distribution. classlist contains a number of class names which BCEL loads dynamically (using string references, so that autojar can't handle them automatically).

10. Bugs

Please report bugs via the SourceForge bug tracking system.
top