Reflections lib for Java: find all classes in a package

In addition 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 are subclasses of a given type. The source code looks like this: from the answer to a related 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 unnoticed for a while, I just discovered that it will only find classes that subclass a different type inside this package. It will not find classes that subclasses externally defined classes from, say, another user package.

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

+4
source share
3 answers

I wrote a library called Rebound (as opposed to Reflections) that looks for subclasses of a given type and package prefix. If you set the prefix to empty, it will look for each class in the classpath, for example.

 import gigadot.exp.reflects.core.Processor; Rebound r = new Rebound(""); Set<Class<? extends Processor>> classes = r.getSubClassesOf(Processor.class); 

But you have to be careful, because finding everything in the class path is a slow process.

A library is much simpler than Reflections, and may not do what you want. I wrote this because of my disappointment when I sent my bug report, but no one is trying to solve the problem.

+6
source

The reason for this is that

 ref.getSubtypesOf(Object.class); 

returns only direct subclasses of the object. If you want to get all classes from a scanned package, you must 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 bit hacky, but this is the only way I've found so far. Here's a little explanation of what this does: When Reflections is done with a scan, it puts all the elements in a map with multiple values. In the sample code that I inserted, the results are placed inside the map with the following keys:

 SubTypesScanner, ResourcesScanner, TypeElementsScanner 

ResourceScanner excludes all files ending with .class. TypeElementsScanner is a map with a key containing the name of the class, and the value of the fields, etc. Therefore, if you want to get only class names, you basically get a set of keys and later, convert it to a set if classes. SubTypesScanner is also a map with the key of all superclasses (including Object and interfaces) and values ​​- classes that implement / extend these interfaces / classes.

You can also use SubTypesScanner, if you like, by iterating over the key set and getting all the values, but if a particular class implements an interface, you will have to deal with duplicate objects (as each class extends Object).

Hope this helps.

+2
source

In my case, this code is great for loading external API classes, but not sure why it doesn’t work for an embedded package such as "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")))); 
0
source

Source: https://habr.com/ru/post/1435099/


All Articles