Classpath-Kontrolle mit JWhich

Spurensuche

Sebastian Eschweiler

Wer in der Vergangenheit bereits mit umfangreicheren Java-Projekten in Kontakt gekommen ist, wird schnell auf Probleme im Umgang mit dem Classpath gestoßen sein. Insbesondere dort, wo viele unterschiedliche Bibliotheken zum Einsatz kommen, kann es sehr schnell passieren, dass der Programmierer den Überblick über den gesamten Classpath verliert. JWhich versucht mit sehr einfachen Mitteln, die Übersicht über den Classpath zurückzugewinnen.

Zunächst stellt sich natürlich die Frage, wofür einen Classpath und was ist ein Classpath? Die CLASSPATH-Variable ist eine System-Variable, die Pfadangaben enthält, unter denen die verschiedenen Java-Klassen zu finden sind, die in ein Projekt mit einbezogen werden sollen. Sowohl der Java-Compiler als auch der Java-Interpreter beziehen ihre Informationen aus den Angaben des Classpath.

Der Classpath nimmt als Angabe Verzeichnisse (mit enthaltenen Java-Class-Dateien) oder Archive (JAR-Dateien) auf. Wie die CLASSPATH-Variable im Einzelnen zu setzen ist, hängt weitgehend vom verwendeten Betriebssystem ab. So wird unter Windows das Semikolon als Trennzeichen zwischen den einzelnen Pfadangaben verwendet und unter Unix / Linux ein Doppelpunkt.

(Windows) set CLASSPATH=C:javalibssomelibtest.jar;.
(Linux bash-Shell) export CLASSPATH=/home/user/javalibs/somelib/test.jar:.

Um nun eine bestimmte Klasse zu finden, wird ein so genannter Classloader eingesetzt. Dieser Vorgang bleibt für den Benutzer unsichtbar und wird von der JVM verwaltet und durchgeführt. In der Regel benötigt eine Applikation mehrere Classloader, die in einer Baumhierarchie organisiert sind. Hierbei hat jeder Classloader einen Elternteil, an welchen er Anfragen weiterreichen kann, falls diese nicht direkt beantwortet werden können. Die Hierarchie ist so angelegt, dass bei der Suche nach einer bestimmten Klasse, zunächst die Einträge der CLASSPATH-Variablen durchlaufen werden. Einträge, die zuerst im Classpath erscheinen, werden auch zuerst nach den betreffenden Klassen durchsucht. Diese – zunächst sehr einfache Tatsache – bereitet in der Praxis aber immer wieder Probleme, da es ja durchaus passieren kann, dass sich zwei Klassen mit identischem Namen im Classpath befinden. Hier stellt sich dann jeweils die Frage, ob die zuerst gefundene Version auch die richtige Version der Klasse darstellt.

Sobald Archive von Fremdherstellern mit eigenen Klassen innerhalb der CLASSPATH-Variablen gemischt werden, ergeben sich die ersten Fallen, denn nur selten haben Sie dann noch einen Überblick, welche Klassen momentan im Classpath enthalten sind. Somit kann es leicht passieren, dass Klassen mit gleichem Namen mehrfach vorkommen und jeweils nur immer die Klasse ausgewählt wird, die sich als Erstes im Classpath befindet.

/usr/lib/java2/bin/java

Wir erfahren somit, dass sich der Java-Interpreter unterhalb des Verzeichnisses /usr/lib/java2/bin befindet.

JWhich verfolgt eben diesen Ansatz zum Auffinden von Java-Klassen. Im Prinzip stellt sich beim Zugriff auf Klassen über den Classpath die Frage, welche Klasse letztendlich zum Einsatz kommt. Am einfachsten lässt sich diese Frage durch die Ausgabe des vollständigen Pfades zur jeweiligen Class-Datei beantworten. Somit können Sie immer sicher sein, dass nicht noch eine weitere Klasse mit demselben Namen existiert, die sich in einem anderen Verzeichnis bzw. JAR-Archiv befindet – womöglich von einem Dritthersteller. Denkbar wäre also ein Aufruf der folgenden Art:

Class 'javax.servlet.http.HttpServlet' found in '/home/seb/java/lib/servlet.jar!/javax/servlet/http/HttpServlet.class'

JWhich ist als Open-Source-Projekt verfügbar und ist auf www.clarkware.com/software/jwhich.zip [1]zu finden. Entwickelt und initiiert wurde JWhich von Mike Clark. Da es sich bei JWhich um ein kleineres und überschaubares Projekt handelt, bietet es sich an dieser Stelle an, einen kurzen Blick auf die Implementierung zu werfen. In Listing 1 sehen Sie den leicht gekürzten Quellcode der JWhich-Klasse.

Listing 1

java.net.URL classUrl = JWhich.class.getResource(resource);

Hierzu wird der Classloader der JWhich-Klasse eingesetzt. Nun kann anhand der Überprüfung des classUrl-Objektes entschieden werden, ob die Anfrage an den Classloader erfolgreich war oder der Rückgabewert null geliefert wurde. In letzterem Fall bedeutet die Rückgabe, dass vom Class loader keine geeignete Klasse ermittelt werden konnte – folglich keine Klasse mit entsprechendem Namen im Classpath enthalten ist. Das Programm reagiert auf diesen Fall mit einer entsprechenden Ausgabe.

Neben der Methode jwhich(String className), die das Auffinden einer übergebenen Klasse im Classpath umsetzt, existiert zusätzlich noch die Methode validate(). Ausgeführt wird diese Methode nur dann, wenn beim Aufruf von JWhich zusätzlich der Parameter -validate mit angegeben wurde. validate() stellt in diesem Fall sicher, dass der übergebene Classpath auch gültig ist. Hierzu wird zunächst eine Zerlegung in die einzelnen Bestandteile des Klassenpfades vorgenommen:

if (!f.exists())
{
System.out.println("n'" + element + "' " + "does not exist.");
}

Mike Clark zeigt mit JWhich, wie auf einfache Weise mehr Durchblick im Programmieralltag geschaffen werden kann. JWhich bietet schnelle Informationen zu Classpath-Informationen und stellt so sicher, dass Klassenvertauschungen durch doppeltes Auftauchen im CLASSPATH vermieden werden können. Besonders bei umfangreichen Projekten, die auf viele Bibliotheken und Klassen von Drittherstellern zurückgreifen, kann dieses Tool einen guten Überblick verschaffen. Schnell ist es passiert, dass gleiche Klassen mit unterschiedlichen Versionen mehrfach im Classpath vorkommen und deshalb Änderungen keine Wirkung zeigen, weil weiterhin eine frühere Version der Klasse benutzt wird.

Falls Sie also beim nächsten Mal nicht sicher sein sollten, ob eventuelle Konflikte durch den Classpath hervorgerufen werden – probieren Sie es einfach mal mit JWhich.

Geschrieben von
Sebastian Eschweiler
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.