Classpath beim Aufruf über java -jar
Christian Seiler
- java
Hallo allerseits,
Ich habe folgendes Java-Problem: Ich verwende in einem Projekt Xerces als XML-Parser. Der kommt ja in einer schönen JAR-Datei xercesImpl.jar. Wenn ich nun meinen Code, der Xerces verwende, auch in eine JAR-Datei packe, ein Manifest erzeuge und dann mittels
java -cp xercesImpl.java -jar meinprojekt.jar
versuche, mein Projekt aufzurufen, beschwert er sich, dass er Xerces nicht findet (die erste Xerces-Klasse, die er laden will, findet er nicht, dabei bricht er auch ab).
Ich habe mir daher mal folgenden Testcase gebastelt:
http://www.christian-seiler.de/temp/java-classpath-test.zip
Da drin ist ein Ant-Buildfile, das zwei .jar-Dateien erzeugt. Im folgenden der Code nochmal hier im Forum:
Es gibt zwei Pakete: example.a und example.b. Alle Klassen in example.a werden ins Paket example-a.jar gepackt, alle Klassen in example.b ins Paket example-b.jar.
In src/example/a befindet sich eine Datei Main.java mit folgendem Code:
package example.a;
public class Main {
public static void main (String [] args) throws Exception {
System.out.println ("Class path: " + System.getProperty ("java.class.path"));
if (args.length >= 1) {
System.out.println ("Trying to load: " + args[0]);
Class test1 = Class.forName (args[0]);
}
}
}
Zusätzlich habe ich folgendes Manifest für die example-a.jar-Datei:
Main-Class: example.a.Main
In src/example/b befindet sich eine Datei Test.java mit folgedem Code:
package example.b;
public class Test {
}
Der Testcase ist im Prinzip sehr billig: Die Main-Klasse des example.a-Pakets versucht die Klasse zu laden, deren Namen als erster Parameter übergeben wird.
Sobald man die *.jar mal erzeugt hat, kann man sich davon überzeugen, dass es funktioniert:
java -cp example-a.jar:example-b.jar example.a.Main example.a.Main
Ergibt:
Class path: example-a.jar:example-b.jar
Trying to load: example.a.Main
Ich kann auch problemlos aus example-b.jar eine Klasse laden:
java -cp example-a.jar:example-b.jar example.a.Main example.b.Test
Ergibt:
Class path: example-a.jar:example-b.jar
Trying to load: example.b.Test
Wenn ich nun aber -jar verwende und eine Klasse aus dem example-a.jar laden will (z.B. wieder Main selbst), dann funktioniert das auch noch:
java -cp example-b.jar -jar example-a.jar example.a.Main
Ergibt:
Class path: example-a.jar
Trying to load: example.a.Main
Aber hier sieht man schon: Der Classpath ist hier nur example-a.jar, example-b.jar fehlt! Und deswegen fliegt auch folgender Aufruf auf die Schnauze:
java -cp example-b.jar -jar example-a.jar example.b.Test
Ergibt:
Class path: example-a.jar
Trying to load: example.b.Test
Exception in thread "main" java.lang.ClassNotFoundException: example.b.Test
...
[Die Umgebungsvariable CLASSPATH zu setzen ändert auch nichts.]
Meine Frage nun: Funktioniert das -jar grundsätzlich nicht mit einem zusätzlichen Classpath? Oder funktioniert das doch und man muss nur ein paar Dinge beachten?
Die Doku sagt lediglich lapidar:
| You can only specify one JAR file, which must contain all the application-specific code.
Das könnte man so lesen, als dass das wirklich nicht geht. Interpretiere ich das richtig?
Ja, ich weiß, ich kann selbst java.class.path ändern / mir mit einem java.net.URLClassLoader einen zusätzlichen ClassLoader erzeugen, den ich zum Laden der Klassen aus example-b.jar verwenden kann, aber das fände ich dann doch irgendwie etwas blöd...
Viele Grüße,
Christian
Hallo allerseits,
Im Chat habe ich ein paar Tipps bekommen und zusammenfassend kann man folgendes sagen:
1. -jar setzt -cp wirklich außer Kraft.
2. Man kann im Manifest einen Eintrag Class-Path: datei1.jar datei2.jar anlegen, der dann automatisch andere .jars nachlädt (natürlich nur wenn der relative oder absolute Pfad dieser jars bezogen auf das aktuelle jar bekannt ist).
3. Ich werde jetzt wohl bei java -cp jar1:jar2:... mainklasse parameter bleiben.
Viele Grüße,
Christian