mtrc
mtrc

Reputation: 1345

Reflections lib for Java: find all classes in a package

Further to the question posted here: Can you find all classes in a package using reflection? I started using the Reflections library to find all classes that subclass a given type. The source code looks like this, from an answer to the linked SO question:

Reflections ref = new Reflections(new ConfigurationBuilder()
    .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
    .setUrls(ClasspathHelper.forPackage("org.somepackage"))
    .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.somepackage"))));

ref.getSubtypesOf(Object.class);

However, after using this code obliviously for a while, I've just discovered that it will only find classes that subclass another type within this package. It won't find classes that subclass externally defined classes, say from another user-defined package.

I'm not sure how to get around this using the Reflections library. I want all classes that declare their package as 'org.somepackage', regardless of what their supertype is. Any help?

Upvotes: 7

Views: 7285

Answers (3)

Masud Rahman
Masud Rahman

Reputation: 1062

In my case, this code works fine to load the classes of an external API, but not sure why it does not work for a built-in package like 'java.util'.

Reflections reflections = new Reflections(new ConfigurationBuilder()
                .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
                .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[2])))
                .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.reflections"))));

Upvotes: 1

vdimitrov
vdimitrov

Reputation: 1111

The reason for this is, that

ref.getSubtypesOf(Object.class);

only returns the direct subclasses of Object. If you want to get all the classes from a scanned package, you should do the following:

Reflections ref = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner(), new TypeElementsScanner())
...
Set<String> typeSet = reflections.getStore().getStoreMap().get("TypeElementsScanner").keySet();
HashSet<Class<? extends Object>> classes = Sets.newHashSet(ReflectionUtils.forNames(typeSet, reflections
            .getConfiguration().getClassLoaders()));

This may look a little hackish but it's the only way I found so far. Here's a little explanation of what this does: When Reflections is done with the scanning, it puts all the elements in a multi-value map. In the code example that I pasted, the results are put inside a map with the following keys:

SubTypesScanner, ResourcesScanner, TypeElementsScanner

The ResourceScanner excludes all files ending with .class. The TypeElementsScanner is a map with a key holding the name of a class, and a value of the fields etc. So if you want to get only the class names, you basically get the key set and later on, convert it to a set if classes. The SubTypesScanner is also a map, with a key of all the super classes (including Object and interfaces) and values - the classes implementing/extending those interfaces/classes.

You can also use the SubTypesScanner if you wish, by iterating the keyset and getting all the values, but if a certain class implements an interface, you will have to deal with duplicate entities (as every class extends Object).

Hope that helps.

Upvotes: 3

gigadot
gigadot

Reputation: 8969

I wrote a library called Rebound (as opposed to Reflections) which searches for the subclasses of a given type and package prefix. If you set the prefix empty, it will search every class under the classpath, e.g.

import gigadot.exp.reflects.core.Processor;

Rebound r = new Rebound("");
Set<Class<? extends Processor>> classes = r.getSubClassesOf(Processor.class);

But you should be careful, because searching everything in the classpath is a slow process.

The library is much simpler than Reflections and might not do what you want. I wrote this due to my frustration when I submitted my bug report but no one there tries to solve the problem.

Upvotes: 6

Related Questions