Retrieving all classes from the classpath

In order to prevent initialization errors caused by loading certain classes at the wrong time and avoid loading all classes into memory, you can utilize utility classes from the Guava library’s package. JProfiler allows you to attach to a running JVM or load a heap dump file to obtain JVM-related metrics, such as the names of all loaded classes. This is the third solution for using it.


Solution 1:

Pass an empty

String

to

ClassLoader#getResources()

to obtain all classpath roots.

Enumeration roots = classLoader.getResources("");

To form a

File

, simply follow these steps using

URL

as a basis.

File root = new File(url.getPath());

Obtain a comprehensive directory listing by utilizing

File#listFiles()

.

for (File file : root.listFiles()) {
    // ...
}

The conventional techniques coded as

java.io.File

can be utilized for identifying whether it is a directory and for obtaining the file name.

if (file.isDirectory()) {
    // Loop through its listFiles() recursively.
} else {
    String name = file.getName();
    // Check if it's a .class file or a .jar file and handle accordingly.
}

Based on the specific functional requirement, it appears that the Reflections library is the more appropriate choice.


Solution 2:


Below is the code I wrote, which should work fine for most cases. However, if you’re utilizing an unconventional classpath, it may not capture everything. It merely retrieves the names of the classes and does not load them. This is done to avoid loading all classes into memory and to prevent initialization errors that some classes in my company’s codebase were causing when loaded at the incorrect time.

public interface Visitor {
    /**
     * @return {@code true} if the algorithm should visit more results,
     * {@code false} if it should terminate now.
     */
    public boolean visit(T t);
}
public class ClassFinder {
    public static void findClasses(Visitor visitor) {
        String classpath = System.getProperty("java.class.path");
        String[] paths = classpath.split(System.getProperty("path.separator"));
        String javaHome = System.getProperty("java.home");
        File file = new File(javaHome + File.separator + "lib");
        if (file.exists()) {
            findClasses(file, file, true, visitor);
        }
        for (String path : paths) {
            file = new File(path);
            if (file.exists()) {
                findClasses(file, file, false, visitor);
            }
        }
    }
    private static boolean findClasses(File root, File file, boolean includeJars, Visitor visitor) {
        if (file.isDirectory()) {
            for (File child : file.listFiles()) {
                if (!findClasses(root, child, includeJars, visitor)) {
                    return false;
                }
            }
        } else {
            if (file.getName().toLowerCase().endsWith(".jar") && includeJars) {
                JarFile jar = null;
                try {
                    jar = new JarFile(file);
                } catch (Exception ex) {
                }
                if (jar != null) {
                    Enumeration entries = jar.entries();
                    while (entries.hasMoreElements()) {
                        JarEntry entry = entries.nextElement();
                        String name = entry.getName();
                        int extIndex = name.lastIndexOf(".class");
                        if (extIndex > 0) {
                            if (!visitor.visit(name.substring(0, extIndex).replace("/", "."))) {
                                return false;
                            }
                        }
                    }
                }
            }
            else if (file.getName().toLowerCase().endsWith(".class")) {
                if (!visitor.visit(createClassName(root, file))) {
                    return false;
                }
            }
        }
        return true;
    }
    private static String createClassName(File root, File file) {
        StringBuffer sb = new StringBuffer();
        String fileName = file.getName();
        sb.append(fileName.substring(0, fileName.lastIndexOf(".class")));
        file = file.getParentFile();
        while (file != null && !file.equals(root)) {
            sb.insert(0, '.').insert(0, file.getName());
            file = file.getParentFile();
        }
        return sb.toString();
    }
}

To use it:

ClassFinder.findClasses(new Visitor() {
    @Override
    public boolean visit(String clazz) {
        System.out.println(clazz)
        return true; // return false if you don't want to see any more classes
    }
});


Solution 3:


The Guava library’s

com.google.common.reflect

package offers utility classes that can be utilized. For example, to obtain all classes within a specific package.

    ClassLoader cl = getClass().getClassLoader();
    Set classesInPackage = ClassPath.from(cl).getTopLevelClassesRecursive("com.mycompany.mypackage");

Although brief, the cautions mentioned in other responses remain applicable. Essentially, this method can solely detect classes that have been loaded by a conventional ClassLoader, such as

URLClassLoader

.

Frequently Asked Questions