Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Get a list of all Classes loaded in the JVM

People also ask

How classes are loaded in JVM?

In order to actually load a class, the JVM uses Classloader objects. Every already loaded class contains a reference to its class loader, and that class loader is used to load all the classes referenced from that class.

How do I get all classes in a classpath?

You can get all classpath roots by passing an empty String into ClassLoader#getResources() . Enumeration<URL> roots = classLoader. getResources("");

How many class loaders are present in JVM?

When the JVM is started, three class loaders are used: Bootstrap class loader. Extensions class loader. System class loader.

How can you directly access all classes in the package in Java?

Since Java enforces the most restrictive access, we have to explicitly declare packages using the export or open module declaration to get reflective access to the classes inside the module.


It's not a programmatic solution but you can run

java -verbose:class ....

and the JVM will dump out what it's loading, and from where.

[Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar]
[Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]

See here for more details.


using the Reflections library, it's easy as:

Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false));

That would scan all classes in the url/s that contains my.pkg package.

  • the false parameter means - don't exclude the Object class, which is excluded by default.
  • in some scenarios (different containers) you might pass the classLoader as well as a parameter.

So, getting all classes is effectively getting all subtypes of Object, transitively:

Set<String> allClasses = 
    reflections.getStore().getSubTypesOf(Object.class.getName());

(The ordinary way reflections.getSubTypesOf(Object.class) would cause loading all classes into PermGen and would probably throw OutOfMemoryError. you don't want to do it...)

If you want to get all direct subtypes of Object (or any other type), without getting its transitive subtypes all in once, use this:

Collection<String> directSubtypes = 
    reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName());

There are multiple answers to this question, partly due to ambiguous question - the title is talking about classes loaded by the JVM, whereas the contents of the question says "may or may not be loaded by the JVM".

Assuming that OP needs classes that are loaded by the JVM by a given classloader, and only those classes - my need as well - there is a solution (elaborated here) that goes like this:

import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

public class CPTest {

    private static Iterator list(ClassLoader CL)
        throws NoSuchFieldException, SecurityException,
        IllegalArgumentException, IllegalAccessException {
        Class CL_class = CL.getClass();
        while (CL_class != java.lang.ClassLoader.class) {
            CL_class = CL_class.getSuperclass();
        }
        java.lang.reflect.Field ClassLoader_classes_field = CL_class
                .getDeclaredField("classes");
        ClassLoader_classes_field.setAccessible(true);
        Vector classes = (Vector) ClassLoader_classes_field.get(CL);
        return classes.iterator();
    }

    public static void main(String args[]) throws Exception {
        ClassLoader myCL = Thread.currentThread().getContextClassLoader();
        while (myCL != null) {
            System.out.println("ClassLoader: " + myCL);
            for (Iterator iter = list(myCL); iter.hasNext();) {
                System.out.println("\t" + iter.next());
            }
            myCL = myCL.getParent();
        }
    }

}

One of the neat things about it is that you can choose an arbitrary classloader you want to check. It is however likely to break should internals of classloader class change, so it is to be used as one-off diagnostic tool.


An alternative approach to those described above would be to create an external agent using java.lang.instrument to find out what classes are loaded and run your program with the -javaagent switch:

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class SimpleTransformer implements ClassFileTransformer {

    public SimpleTransformer() {
        super();
    }

    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
        System.out.println("Loading class: " + className);
        return bytes;
    }
}

This approach has the added benefit of providing you with information about which ClassLoader loaded a given class.