Get a list of all classes loaded in the JVM
Asked Answered
O

13

86

I would like to get a list of all the classes belonging to a certain package as well as all of their children. The classes may or may not be already loaded in the JVM.

Ottavia answered 30/3, 2010 at 20:16 Comment(0)
O
-9

Well, what I did was simply listing all the files in the classpath. It may not be a glorious solution, but it works reliably and gives me everything I want, and more.

Ottavia answered 31/3, 2010 at 16:0 Comment(3)
Can you give a code snippet? that way others can benefit from your solution. thanksWarfeld
@jtzero: I do not know what OP used, but for me System.getProperty("java.class.path") works well.Hiss
Please read How do I write a good answer? before attempting to answer more questions.Sphagnum
T
126

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.

Tm answered 30/3, 2010 at 20:20 Comment(7)
The questions asks "Get a list of all Classes loaded in the JVM", not the list of ".jar" loaded.Maritamaritain
The above output details the jars opened and the subsequent class loadingTm
Right, in the first moment I only have read ".jar" in the extreme right ... my mistake. sorry!Maritamaritain
is this a hack of some sorts? would this verbose level get adjusted by user configuration?Siderosis
if there's one JVM per java process, i.e. there can be many JVM(java process) running on one machine, then which JVM does your command output correspond?Siderosis
You run the above as part of the JVM invocation i.e. its start-up command line arguments. So you can do the above for any/all of your JVMsTm
@BrianAgnew unfortunately I wanted to list classes loaded by already running JVM...I have no control over existing JVM start command parameters.Siderosis
U
33

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());
Unformed answered 9/3, 2013 at 16:25 Comment(3)
What Reflections lib version are you using? This example does not work with Reflections 0.9.5.Ieyasu
Nevermind, just got it working using reflections-0.9.9-RC1-uberjarIeyasu
You only have to go through the suffering that is adding another library to your project. You're not allowed to use the word "easy" when the language in question in Java. You gave me hope thinking this was the standard reflection that's part of the JDK.Bipinnate
C
25

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.

Cyanocobalamin answered 1/12, 2014 at 8:14 Comment(9)
@Cyanocobalamin What is the difference between using Thread.currentThread().getContextClassLoader() vs. CPTest.class.getClassLoader()? Is there a reason you preferred getting the ClassLoader from the Thread object?Raster
@MichaelPlautz the difference is that the other is the thread context class loader and the other is the class loader used by given class. There are a lot of different classloaders used by java, which I won't elaborate in this comment space. The reason is that it is assumed that thread context classloader parent relation would include the whole of JVM, whereas class classloader might not.Cyanocobalamin
You can avoid the while loop by just doing ClassLoader.class.getDeclaredField("classes").Wilde
In android, I get java.lang.NoSuchFieldException: No field classes in class Ljava/lang/ClassLoader, any ideas why?Entomophilous
@NathanH in android there is no such field. Compare android classloader with java se classloaderCyanocobalamin
@Cyanocobalamin "it is assumed that thread context classloader parent relation would include the whole of JVM, whereas class classloader might not". This may lead me to an answer to this question: https://mcmap.net/q/243589/-why-are-there-two-instances-created-of-a-singleton-java-class/9165920. Can you guide me to some documentation about this? // Do you have an idea how we can proceed to get all classloaders and all classes loaded by them in Android DVM?Rudolf
@IrfanLatif I haven't got much experience with android, so can't help you there. In general, a new question is for new topics :)Cyanocobalamin
@Cyanocobalamin the question is already there. Thanks btwRudolf
this answer for java11+ is not validMegacycle
E
11

I'd also suggest you write a -javagent agent, but use the getAllLoadedClasses method instead of transforming any classes.

To synchronize with your client code (Normal Java code), create a socket and communicate with the agent through it. Then you can trigger a "list all classes" method whenever you need.

Endue answered 30/3, 2010 at 20:33 Comment(0)
P
10

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.

Paronymous answered 30/3, 2010 at 20:30 Comment(0)
D
5

List of all Classes loaded in the JVM

From Oracle doc you can use -Xlog option that has a possibility to write into file.

java -Xlog:class+load=info:classloaded.txt
Dinner answered 30/3, 2019 at 15:19 Comment(1)
Doesn't work with my java 8.Pontiff
V
4

There's another possibility using VM.class_hierarchy, available since JDK 8 (tested on 1.8.0_322).

$ jcmd 44506 VM.class_hierarchy

This will give a result like that :

44506:
java.lang.Object/null
|--com.intellij.psi.impl.source.tree.JavaElementType$$Lambda$1163/0x0000000800cd86d8/0x0000600002f012c0
|--com.intellij.ide.IdeTooltipManager/0x0000600002f2c6e0
|--sun.security.ssl.SSLBasicKeyDerivation$SecretSizeSpec/null
|--com.intellij.openapi.editor.impl.view.EditorSizeManager$$Lambda$2094/0x0000000801774c38/0x0000600002f2c6e0
|--com.intellij.psi.util.CachedValueProfiler$EventPlace/0x0000600002f2c6e0 (intf)
|--io.ktor.utils.io.internal.ReadWriteBufferStateKt/0x0000600002fcd680
|--com.intellij.javascript.nodejs.library.core.codeInsight.NodePredefinedReferenceErrorUpdater/0x0000600002f13660
|--com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl$MyAsyncFileListener/0x0000600002f2c6e0
|--java.lang.management.ManagementFactory$PlatformMBeanFinder$$Lambda$89/0x000000080013e0b0/null
|--org.intellij.plugins.markdown.ui.preview.MarkdownHtmlPanelProvider$AvailabilityInfo/0x0000600002f0ada0
|  |--org.intellij.plugins.markdown.ui.preview.MarkdownHtmlPanelProvider$AvailabilityInfo$2/0x0000600002f0ada0
|  |--org.intellij.plugins.markdown.ui.preview.MarkdownHtmlPanelProvider$AvailabilityInfo$1/0x0000600002f0ada0
|--java.lang.invoke.LambdaForm$DMH/0x000000080012a800/null
|--git4idea.status.GitStagingAreaHolder$$Lambda$2907/0x0000000801d2e690/0x0000600002f41cc0
|--com.intellij.lang.javascript.refactoring.extractSuper.JSCustomExtractInterfaceHandler/0x0000600002f13660 (intf)
|--javax.xml.transform.stream.StreamSource/null
...
Visser answered 10/7, 2022 at 14:45 Comment(0)
M
3

Run your code under a JRockit JVM, then use JRCMD <PID> print_class_summary

This will output all loaded classes, one on each line.

Melvinamelvyn answered 11/11, 2011 at 17:7 Comment(0)
F
3

One way if you already know the package top level path is to use OpenPojo

final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);

Then you can go over the list and perform any functionality you desire.

Freiburg answered 28/8, 2012 at 1:54 Comment(0)
D
3

This program will prints all the classes with its physical path. use can simply copy this to any JSP if you need to analyse the class loading from any web/application server.

import java.lang.reflect.Field;
import java.util.Vector;

public class TestMain {

    public static void main(String[] args) {
        Field f;
        try {
            f = ClassLoader.class.getDeclaredField("classes");
            f.setAccessible(true);
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Vector<Class> classes =  (Vector<Class>) f.get(classLoader);

            for(Class cls : classes){
                java.net.URL location = cls.getResource('/' + cls.getName().replace('.',
                '/') + ".class");
                System.out.println("<p>"+location +"<p/>");
            }
        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}
Delaminate answered 15/10, 2017 at 6:54 Comment(1)
this answer for java11+ is not validMegacycle
G
2

You might be able to get a list of classes that are loaded through the classloader but this would not include classes you haven't loaded yet but are on your classpath.

To get ALL classes on your classpath you have to do something like your second solution. If you really want classes that are currently "Loaded" (in other words, classes you have already referenced, accessed or instantiated) then you should refine your question to indicate this.

Gourley answered 30/3, 2010 at 20:21 Comment(0)
B
1

If you don't want any libraries and need this information given to you at runtime, you can use this for Java 11+. It finds all system modules loaded at runtime, iterates over their entries (path names) and collects class items.

public static List<String> getSystemClasses() {
    // Errorables is a util class to ignore exceptions on lambda types, easy enough to implement yourself
    return ModuleFinder.ofSystem().findAll().stream()
               .map(modRef -> Errorables.silent(modRef::open)) // open reader to each module
               .flatMap(modReader -> Errorables.silent(modReader::list)) // list all items in the module
               .filter(s -> s.endsWith(".class") && s.indexOf('-') == -1) // retain only classes (except module-info or package-info)
               .map(s -> s.substring(0, s.length() - 6)) // cut off '.class' from the path
               .collect(Collectors.toList());
}

If you need non-system classes then there are some conditions to consider. In both situations you can use a class reference to something in your project to get the needed context to find other classes.

If you want only the currently loaded classes, you can use reflection to access the Vector<Class<?>> classes in ClassLoader. This will not include classes from libraries and such that have not yet been initialized.

screenshot of only the initialized classes

If you want all classes of all libraries you have in a project then you'll want to use reflection to access the AppClassLoader's URLClassPath ucp. This will hold a ArrayList<URL> path containing URL's pointing to every directory/jar/etc holding referenced resources. Navigating those you can use path-walking to collect the names of class entries similar to the code snippet above.

screenshot of file path uris to referenced libraries

Bigler answered 15/7, 2022 at 11:40 Comment(0)
O
-9

Well, what I did was simply listing all the files in the classpath. It may not be a glorious solution, but it works reliably and gives me everything I want, and more.

Ottavia answered 31/3, 2010 at 16:0 Comment(3)
Can you give a code snippet? that way others can benefit from your solution. thanksWarfeld
@jtzero: I do not know what OP used, but for me System.getProperty("java.class.path") works well.Hiss
Please read How do I write a good answer? before attempting to answer more questions.Sphagnum

© 2022 - 2024 — McMap. All rights reserved.