How to find which jars and in what order are loaded by a classloader?

59,474

Solution 1

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.

Solution 2

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]

Solution 3

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...

Solution 4

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);
}
Share:
59,474
Marina
Author by

Marina

Updated on July 09, 2022

Comments

  • Marina
    Marina almost 2 years

    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.

  • Marina
    Marina about 14 years
    Thanks, Steve - yes, I tried that option and it works fine if you are just interested in knowing which classloader and from what .jar loaded a specific class. The output gets too overwhelming though, as our application has thousands of classes :). I've used an approach similar to what kdgregory suggested - see below.
  • Marina
    Marina about 14 years
    Thanks, kdgregory. This is the approach I finally used - basically I wrote a utility that figures out the classloader hierarchy at runtime and queries each classloader what list of resources they 've loaded using the getURLs() method if available. It worked well for both WLS and WAS. In the case of WLS, their own classloaders do not extend URLClassloader, but they do have a different method, getClassPath(), which returns an ordered list of classpath entries. And all WAS classloaders seem to extend the URLClassloader, so getURLs() worked fine. Have not tried it on JBoss yet. Marina
  • tribbloid
    tribbloid about 2 years
    that's a lot of reflection, will become obsolete in no time after Java 9 upgrade