Automatisches Erzeugen von Java-Archiven
AllgemeinesKommandozeilenversionEclipse-Plugin
Bernd Eggink, monoped@users.sourceforge.net Projektseite: SourceForge.net
Beispiele
Standardfall
Ein Programm besteht aus der Hauptklasse example.std.Std und weiteren Klassen, die im Verzeichnis classes liegen. Außerdem werden Klassen aus dem Archiv libs/lib1.jar benutzt. Das Programm benötigt ferner die Grafikdatei img1.png, die im Archiv libs/imgs.jar liegt. Die Manifestdatei std.mf enthält einen gültigen Main-Class - Eintrag. Das Ausgabe-Archiv soll std.jar heißen. Das Kommando lautet dann:
java -jar autojar.jar -o std.jar -vc "classes:libs/lib1.jar" \
    -p libs/imgs.jar -m std.mf img1.png
Alternativ könnte man schreiben:
java -jar autojar.jar -o std.jar -vc "classes:libs/*.jar" -m std.mf \
    -b img1.png
Reflection
Die Klassen- und Resourcedateien eines Programms liegen im Verzeichnis classes und im Archiv my.jar. Die Hauptklasse com.wow.MyApp lädt dynamisch eine Treiberklasse. Wie diese heißt, weiß man nicht, vermutet sie aber im Archiv drivers.jar. Man verwendet dann probeweise die Option -a und gibt das Archiv mit an:
java -jar autojar.jar -av -o myapp.jar  \
    -c classes:my.jar:drivers.jar com/wow/MyApp.class
Wenn die Ausgabe eine Zeile der Art
* Dynamic loading: class com.wow.MyApp, method init, name="some.nice.Driver" (RESOLVED)
enthält, war der Klassenname some.nice.Driver als Literal angegeben, Autojar hat die Klasse gefunden und eingebunden.
Fehlt das RESOLVED am Ende der Zeile, ist der Namen der Treiberklasse zwar bekannt, aber sie konnte nicht über den Classpath gefunden werden. Wo sie liegt, muss man zunächst (wie auch immer) herausfinden. Angenommen, sie befindet sich in dem Archiv otherdrivers.jar, dann nimmt man dieses mit in den Classpath auf:
java -jar autojar.jar -av -o myapp.jar \
    -c classes:my.jar:drivers.jar:otherdrivers.jar com/wow/MyApp.class

Wird statt dessen eine Zeile der Art

* Dynamic loading, unknown classname:
    class com.wow.MyApp, method init
konnte Autojar den Namen der zu ladenden Klasse nicht herausfinden, weil er nicht als Literal angegeben war. Das letzte Mittel wäre dann, das Programm trotzdem zu starten und auf eine ClassNotFound - Exception zu warten. Dem Fehlertext lässt sich entnehmen, wie die fehlende Klasse heißt; beim nächsten autojar-Aufruf kann sie dann als Dateiparameter mit angegeben werden.
Archive manipulieren
Drei Archive libA.jar, libB.jar und libC.zip sollen zu einem einzigen, libSum.jar, zusammengefasst werden. Dabei sollen Einträge, deren Namen auf .old enden, nicht übernommen werden:
java -jar autojar.jar -o libSum.jar -- -X '*.old' libA.jar libB.jar libC.zip
Wenn in mehreren Quelldateien ein Eintrag mit dem gleichen Namen vorkommt, wird nur der erste übernommen. Das kann man sich z.B. zunutze machen, um eine Klassenbibliothek zu ändern. Angenommen, man möchte in einer umfangreichen Open-Source-Bibliothek libX.jar eine einzige Klasse, etwa a.b.X, verändern. Man besorgt sich dann die Quellen, ändert a/b/X.java und übersetzt nur diese Klasse neu:
javac -d classes -classpath classes:libX.jar a/b/X.java
Danach erzeugt man ein geändertes Archiv libX1.jar mit dem Kommando
java -jar autojar.jar -o libX1.jar -c classes a.b.X.class libX.jar
Man beachte die Reihenfolge der beiden letzten Parameter!
Hilfsarchive für Bibliotheken
Entwicklern soll eine Bibliothek libA.jar zur Verfügung gestellt werden. Die Klassen dieser Bibliothek benötigen einige Klassen aus lib1.jar und lib2.jar. Autojar soll diese Klassen extrahieren und zu einer Hilfsbibliothek libAux.jar zusammenfassen, die dann zusammen mit libA.jar ausgeliefert wird. Der folgende Aufruf erzeugt diese Hilfsbibliothek:
java -jar autojar.jar -o libAux.jar -c lib1.jar:lib2.jar -- -Y libA.jar
Ohne den Prefix -Y würde libAux.jar zusätzlich den gesamten Inhalt von libA.jar enthalten.
Wie Autojar sich selbst erzeugt
Das Archiv autojar.jar ist durch Anwendung von Autojar auf sich selbst entstanden. Das Kommando sieht im Prinzip so aus:
java -classpath classes org.sourceforge.autojar.Autojar \
    -av -c classes:libs/bcel.jar:libs/log4j.jar -p log4j -o autojar.jar \
    -m autojar.mf -- -X .bzr @src/classlist log4j.properties
Erläuterung: Autojar benötigt Klassen aus den Bibliotheken bcel.jar und log4j.jar und muss außerdem die Steuerdatei log4j.properties einbinden, die im Verzeichnis log4j liegt. Da das Projekt unter der Kontrolle von Bazaar ist, gibt es allenthalben Verzeichnisse .bzr, die nicht mit übernommen werden sollen. Viele Klassen des Packages org.apache.bcel.generic werden dynamisch geladen, zwei weitere von log4j. Damit die Kommandozeile nicht zu lang wird, wurden diese Namen zeilenweise in die Datei src/classlist geschrieben.

Eine Alternative, die ohne src/classlist auskommt, könnte so aussehen:

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 .bzr "org.apache.bcel.generic.*.class" \
    log4j.properties org.apache.log4j.ConsoleAppender.class \
    org.apache.log4j.PatternLayout.class 
Hier werden alle Klassen des Packages org.apache.bcel.generic übernommen, einschließlich einiger nicht benötigter, und die beiden log4j-Klassen direkt angegeben. Die entstehende jar-Datei ist um etwa 20K größer.
up
Created 2011-05-10 by mopcoge