PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java Class-Loading Geschichten


Shink
2006-08-03, 16:50:14
Hallo!

Wie bekomme ich aus einer laufenden Java-Applikation solche Sachen raus wie:
- Welche Klassen hab ich im Classpath?
- Welche Klassen sind in einem bestimmten JAR-File?

HellHorse
2006-08-03, 17:51:10
- Welche Klassen hab ich im Classpath?
Von Hand.
- Welche Klassen sind in einem bestimmten JAR-File?
Von Hand (JarFile).

Hab mal so was geschrieben. Mal suchen ob ich es irgendwo finde.

Shink
2006-08-03, 17:56:15
Hmm... und da bist du wirklich der einzige, der auf die Idee gekommen ist, so etwas zu benötigen?
Irgendwie sollte man meinen, die Apache Jakarta-Typen müssten so etwas auch mal gebraucht haben.

Andere Frage: Wie finde ich von Hand heraus, was im Classpath ist?

HellHorse
2006-08-03, 20:46:32
Hmm... und da bist du wirklich der einzige, der auf die Idee gekommen ist, so etwas zu benötigen?
Ich eigentlich auch.
Irgendwie sollte man meinen, die Apache Jakarta-Typen müssten so etwas auch mal gebraucht haben.
Hehe, in der Tat. Ist sicher in irgend einem Projekt irgendwo tief versteckt.


Andere Frage: Wie finde ich von Hand heraus, was im Classpath ist?

public class ClassNameLister {

private static final String fileSeparator;
private static FileFilter directoryFilter;
private static FileFilter classFilesFilter;

static {
fileSeparator = System.getProperty("file.separator");
directoryFilter = new DirectoryFilter();
classFilesFilter = new ClassFilesFilter();
}

public static Set<String> scanClassPath() throws IOException {
String classPath = System.getProperty("java.class.path");
String delimeter = System.getProperty("path.separator");
StringTokenizer tokenizer = new StringTokenizer(classPath, delimeter);
Set<String> classNames = new HashSet<String>();

while (tokenizer.hasMoreTokens()) {
String nextElementName = tokenizer.nextToken();
File nextElement = new File(nextElementName);
if (nextElement.isDirectory()) {
scanDirectory(classNames, nextElement);
} else if (nextElementName.endsWith(".jar")) {
scanJar(nextElementName, classNames);
}
}
return classNames;
}

private static void scanDirectory(Set<String> classNames, File directory) {
scanSubdirectory(classNames, directory, directory);
}

private static void scanSubdirectory(Set<String> classNames, File directory, File parent) {
for (File classFile : directory.listFiles(classFilesFilter)) {
classNames.add(asClassName(classFile, parent));
}

for (File subdirectory : directory.listFiles(directoryFilter)) {
scanSubdirectory(classNames, subdirectory, parent);
}
}

private static void scanJar(String fileName, Set<String> classNames) throws IOException {
JarFile jar = new JarFile(fileName);
Enumeration<JarEntry> entryenum = jar.entries();
while (entryenum.hasMoreElements()) {
JarEntry nextEntry = entryenum.nextElement();
if (!nextEntry.isDirectory() && nextEntry.getName().endsWith(".class")) {
classNames.add(asClassname(nextEntry.getName()));
}
}
}

private static String asClassName(File file, File parentDirectory) {
String absolutePath = file.getAbsolutePath();
String relativePath = absolutePath.substring(parentDirectory.getAbsolutePath().length() + 1);
return asClassname(relativePath);
}

private static String asClassname(String filename) {
return filename.substring(0, filename.length() - 6).replaceAll(fileSeparator, ".");
}


protected static class ClassFilesFilter implements FileFilter {

public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".class");
}
}

protected static class DirectoryFilter implements FileFilter {

public boolean accept(File pathname) {
return pathname.isDirectory();
}

}
}
Sicher nicht der elgetanteste Code, der je geschrieben wurde. Er liefert die voll qulifizierten Klasennamen aller Klassen, inkl. innerer Klassen ($) und anonymer inner Klassen(+).
Das Problem ist dass er nur die Klassennamen liefert. Denn du z.B. nur alle Subklassen einer best. Klasse oder alle Klassen, die ein best. Interface implementieren willst, musst die jede einzeln laden. Das dauert erstens einen Moment und belegt zweitens Speicher in der (knappen) permanent generation.

Ausserdem liefert er auch nicht die Klassen im boot classpath, also alle J2SE Klassen.

BTW, ist dir schon mal aufgefallen, dass JUnit einen eigenen ClassLoader hat?

Abnaxos
2006-08-04, 13:04:30
Wie bekomme ich aus einer laufenden Java-Applikation solche Sachen raus wie:
- Welche Klassen hab ich im Classpath?
- Welche Klassen sind in einem bestimmten JAR-File?

Das geht nicht. Und zwar aus folgendem Grund: Die Klassen können irgendwoher kommen, es gibt nichts, aber auch gar nichts, das besagt, dass die Klassen aus einem JAR-File kommen. Wenn man beispielsweise Drools verwendet, dann werden einige Klassen kurzerhand zur Laufzeit per eingebettetem Eclipse kompiliert. Damit ist es auch nicht möglich, den "Classpath" zu scannen -- möglicherweise, das wird sogar immer häufiger, gibt es bis auf einen kleinen Bootstrapper keinen Classpath in dem Sinn.