Reputation: 4064
I could not find a clear answer to this question elsewhere, so I'll try here:
Is there some way (programmatic or other) to get a list of JARs/classes loaded by an Application Classloader in the precise order they were loaded? By Application Classloader I mean the classloader that loads an EAR application in an applications server (WLS, WAS, JBoss...), but obviously, it applies to any classloader.
So, to generalize, what I would like to find out is the list and order of JARs loaded by a specified classloader. Not individual classes, that is easy enough to find out by calling the classloader.getPackages(), but a list of JAR files that were loaded by this classloader.
Upvotes: 53
Views: 68150
Reputation: 1204
As an alternative way, you can use this code snippet. The result is a file that consist of related jar files to a class-loader and class files that are loaded by an object's class-loaders (chain of class-loaders including its parents until root class-loader). Class-loaders are seperated by stars.
Object obj = this;
ClassLoader classLoader = obj.getClass().getClassLoader();
File file = new File("classlodersClassesJars.txt");
if(file.exists()) {
file.delete();
}
if(classLoader != null) { // to escape from system classes that are loaded by bootstrap class-loader such as String.
do {
try {
Class clClass = classLoader.getClass();
while(clClass != ClassLoader.class){
clClass = clClass.getSuperclass();
}
java.lang.reflect.Field domainField = clClass.getDeclaredField("domains");
java.lang.reflect.Field classesField = clClass.getDeclaredField("classes");
domainField.setAccessible(true);
classesField.setAccessible(true);
HashSet domains = (HashSet<String>) domainField.get(classLoader);
Vector classes = (Vector) classesField.get(classLoader);
FileOutputStream fos = new FileOutputStream("classlodersClassesJars.txt", true);
fos.write(("\n******************** " + classLoader.toString() + "\n").getBytes());
fos.write(Arrays.toString(classes.toArray()).getBytes());
Object[] reverseDomains = domains.toArray();
org.apache.commons.lang.ArrayUtils.reverse(reverseDomains);
fos.write(Arrays.toString(reverseDomains).getBytes());
fos.close();
classLoader = classLoader.getParent();
} catch (Exception exception) {
exception.printStackTrace();
// TODO
}
} while (classLoader.getParent() != null);
}
Upvotes: 1
Reputation: 91
Go through the Protection Domain of the class (the location/certificate combination). e.g. for PDFParser.class you get it like this...
PDFParser.class.getProtectionDomain().getCodeSource().getLocation().toString()
If it is loaded from the jre classes or from endorsed dirs it will throw an exception cos these classes load without protection...
Upvotes: 2
Reputation: 39606
The short answer is no. Classloaders are not required to expose their search logic.
However, if your classloader instance happens to be URLClassLoader or a subclass, then you do have access to the list of jars/directories, via the getURLs()
method. Per the doc for this class, those URLs will be searched in order.
In practice, if you're trying to find out where a class is being loaded from, Steve's answer is probably more useful.
Upvotes: 16
Reputation: 19530
Have you tried to use the JVM option -verbose:class
. It displays all loaded JAR files and classes.
Example:
[Opened C:\Program Files\JDK160~1\jre\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\JDK160~1\jre\lib\rt.jar]
Upvotes: 90