Marina
Marina

Reputation: 4064

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

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

Answers (4)

MMKarami
MMKarami

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

gmournos
gmournos

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

kdgregory
kdgregory

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

Steve
Steve

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

Related Questions