Christian Seiler: Classpath beim Aufruf über java -jar

Beitrag lesen

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