How to Enumerate All Classes in a Package and Add Them to a List

How can I enumerate all classes in a package and add them to a List?

****UPDATE 1 (2012)****

OK, I've finally gotten around to cleaning up the code snippet below. I stuck it into it's own github project and even added tests.

https://github.com/ddopson/java-class-enumerator

****UPDATE 2 (2016)****

For an even more robust and feature-rich classpath scanner, see https://github.com/classgraph/classgraph . I'd recommend first reading my code snippet to gain a high level understanding, then using lukehutch's tool for production purposes.

****Original Post (2010)****

Strictly speaking, it isn't possible to list the classes in a package. This is because a package is really nothing more than a namespace (eg com.epicapplications.foo.bar), and any jar-file in the classpath could potentially add classes into a package. Even worse, the classloader will load classes on demand, and part of the classpath might be on the other side of a network connection.

It is possible to solve a more restrictive problem. eg, all classes in a JAR file, or all classes that a JAR file defines within a particular package. This is the more common scenario anyways.

Unfortunately, there isn't any framework code to make this task easy. You have to scan the filesystem in a manner similar to how the ClassLoader would look for class definitions.

There are a lot of samples on the web for class files in plain-old-directories. Most of us these days work with JAR files.

To get things working with JAR files, try this...

private static ArrayList<Class<?>> getClassesForPackage(Package pkg) {
String pkgname = pkg.getName();
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
// Get a File object for the package
File directory = null;
String fullPath;
String relPath = pkgname.replace('.', '/');
System.out.println("ClassDiscovery: Package: " + pkgname + " becomes Path:" + relPath);
URL resource = ClassLoader.getSystemClassLoader().getResource(relPath);
System.out.println("ClassDiscovery: Resource = " + resource);
if (resource == null) {
throw new RuntimeException("No resource for " + relPath);
}
fullPath = resource.getFile();
System.out.println("ClassDiscovery: FullPath = " + resource);

try {
directory = new File(resource.toURI());
} catch (URISyntaxException e) {
throw new RuntimeException(pkgname + " (" + resource + ") does not appear to be a valid URL / URI. Strange, since we got it from the system...", e);
} catch (IllegalArgumentException e) {
directory = null;
}
System.out.println("ClassDiscovery: Directory = " + directory);

if (directory != null && directory.exists()) {
// Get the list of the files contained in the package
String[] files = directory.list();
for (int i = 0; i < files.length; i++) {
// we are only interested in .class files
if (files[i].endsWith(".class")) {
// removes the .class extension
String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6);
System.out.println("ClassDiscovery: className = " + className);
try {
classes.add(Class.forName(className));
}
catch (ClassNotFoundException e) {
throw new RuntimeException("ClassNotFoundException loading " + className);
}
}
}
}
else {
try {
String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", "");
JarFile jarFile = new JarFile(jarPath);
Enumeration<JarEntry> entries = jarFile.entries();
while(entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if(entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) {
System.out.println("ClassDiscovery: JarEntry: " + entryName);
String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", "");
System.out.println("ClassDiscovery: className = " + className);
try {
classes.add(Class.forName(className));
}
catch (ClassNotFoundException e) {
throw new RuntimeException("ClassNotFoundException loading " + className);
}
}
}
} catch (IOException e) {
throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e);
}
}
return classes;
}

Can you find all classes in a package using reflection?

Due to the dynamic nature of class loaders, this is not possible. Class loaders are not required to tell the VM which classes it can provide, instead they are just handed requests for classes, and have to return a class or throw an exception.

However, if you write your own class loaders, or examine the classpaths and it's jars, it's possible to find this information. This will be via filesystem operations though, and not reflection. There might even be libraries that can help you do this.

If there are classes that get generated, or delivered remotely, you will not be able to discover those classes.

The normal method is instead to somewhere register the classes you need access to in a file, or reference them in a different class. Or just use convention when it comes to naming.

Addendum: The Reflections Library will allow you to look up classes in the current classpath. It can be used to get all classes in a package:

 Reflections reflections = new Reflections("my.project.prefix");

Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);

How can I get a list of all classes within current module in Python?

Try this:

import sys
current_module = sys.modules[__name__]

In your context:

import sys, inspect
def print_classes():
for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj):
print(obj)

And even better:

clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)

Because inspect.getmembers() takes a predicate.

list all class names in a package in python

I will try to dig some code out, but in general :

  1. Walk through the package folders and files using 'os.walk'
  2. For every Python file you find use importlib to import it.
  3. For every imported module use the functions in the 'inspect' standard library module to identify the classes within each imported module.

I don't there is any nice way to import a module based on it's absolute path. The import process works by importing paths which are either relative to the existing module, or relative to an entry in sys.path. An option might be to force add the root of your package into sys.path - and for every file you find work out the dotted module name for the module.

List all classes in a package that implements a given interface

You should use java Reflection

This link offers a tutorial that cover all the thing you can do using Reflection. You can build your code starting from there

List all subpackages of a package (when their classes are loaded dynamically)

Almost certainly the best way to deal with this is to create a list as a build step (probably as a .java file).

Package.getPackage is deprecated.

Package.getPackages is a static method - it isn't doing what you think it's doing.

Both method use the caller's class loader, which is surprising, and isn't much use if you're "really" dynamically loading the classes.

For unloaded classes, I guess you're looking at getting hold of the class path for your class loader (assuming it's a URLClassLoader of some sort) and traversing directories/read jar/zip directories (or the manifest if present).

Modules may be useful - I've not really looked at them.

How I can get list of all classes from given bundle

The name of the classes from the bundle will be in classNameOfCurrentBundle list in the end:

BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
// Getting all the class files (also from imported packages)
Collection<String> resources = bundleWiring.listResources("/", "*.class", BundleWiring.LISTRESOURCES_RECURSE);

List<String> classNamesOfCurrentBundle = new ArrayList<String>();
for (String resource : resources) {
URL localResource = bundle.getEntry(resource);
// Bundle.getEntry() returns null if the resource is not located in the specific bundle
if (localResource != null) {
String className = resource.replaceAll("/", ".");
classNamesOfCurrentBundle.add(className);
}
}

Converting the className to class type:

bundle.loadClass(className);


Related Topics



Leave a reply



Submit