It would seem the answer is obvious:

(new Reflections("package")).getSubTypesOf(SuperClass.class) 

However, this construction does not find all the heirs, if the hierarchy is separated into several packages.

There are the following classes:

 package1.ParentClass extemds SuperClass package2.ChildClass extends ParentClass 

Packages package1 and package2 not nested.

Design

 (new Reflections("package1")).getSubTypesOf(SuperClass.class) 

Expected return package1.ParentClass

But the design

 (new Reflections("package2")).getSubTypesOf(SuperClass.class) 

Our package2.ChildClass will not return, although it is an obvious successor to SuperClass .

I understand. I can manually run through all the classes in the package and collect the necessary ones. But is there really no standard way?

And yet, explain why the default ChildClass not located? For me, this was a very unexpected behavior from org.reflections.Reflections .

UPD : I studied the sources of the org.reflections kernel, everything fell into place. In short, java implements Reflections exactly like this. Each class in the reflection has only a link to the parent. Therefore, the search for subclasses is brute force anyway. Why in this search there are no super classes from other packages - a separate question. So implemented.

For each specific problem you need to use the optimal solution. But I would like to hear about existing solutions that allow you to find all descendants, except java org.reflections.

UPD : Another interesting and easy way.

 Reflections reflections = new Reflections("package1", new SubTypesScanner()) Set<Class<?>> subTypes = new HashSet<>(); for (String className : reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values()) { try { Class subType = Class.forName(className); if (SuperClass.class.isAssignableFrom(subType)) { subTypes.add(subType); } } catch (ClassNotFoundException e) { throw new RuntimeException("Этого не может быть:)", e); } } return subTypes; 

This solution enumerates all classes of the package (except for object heirs)

 reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values() 

and checks to see if they are the heir or implement SuperClass

 SuperClass.class.isAssignableFrom(subType) 

By performance, at least, better than searching all the packages and subsequent filtering

    1 answer 1

    And yet, explain why the default ChildClass is not located?

    The reason is that the ChildClass class is not a direct descendant of SuperClass , but through the ParentClass class.

    Reflections do not go recursively to check "parents-parents" and so on, so to detect the fact of inheritance through the "intermediate" classes, you must download the packages with all the "intermediate" classes. In this case, in order to determine whether ChildClass from SuperClass you must also load ParentClass . Extra classes from the resulting set (Set) can be filtered by package name.

     (new Reflections("package1","package2")) .getSubTypesOf(SuperClass.class) .stream() .filter(c->c.getPackage().getName().equals("package2")).collect(Collectors.toSet()); 

    1) If the package "package1" is unknown, then you can load implementations from all packages and then filter by the required package "package2":

     Set<Class<? extends SuperClass>> s = new Reflections( ClasspathHelper.forClass(SuperClass.class)) .getSubTypesOf(SuperClass.class) .stream() .filter(c->c.getPackage().getName().equals("package2")) .collect(Collectors.toSet()); 

    or

     Set<Class<? extends SuperClass>> s = new Reflections( new ConfigurationBuilder() .setUrls(ClasspathHelper.forClass(SuperClass.class)) .filterInputsBy(new FilterBuilder().excludePackage("package2"))) .getSubTypesOf(SuperClass.class); 

    2) As a more productive alternative, you can use the standard “java core” tools and get all the package class files and check them for the desired heir recursively.

     public static Set<Class<?>> loadClasses(String packageName) throws ClassNotFoundException { Set<Class<?>> classes = new HashSet<>(); URL resource = Thread.currentThread() .getContextClassLoader() .getResource(packageName.replace('.', '/')); File directory = new File(resource.getFile()); if (!directory.exists()) { return classes; } File[] files = directory.listFiles(); if (files == null || files.length == 0) { return classes; } for (File file : files) { //в другие пакеты уходить ненужно if (file.isFile() && file.getName().endsWith(".class")) { classes.add(Class .forName(String.format("%s.%s", packageName, file.getName().substring(0, file.getName().indexOf("."))))); } } return classes; } 

      public static boolean checkAllParents(Class<?> type, Class<?> hasParentType) { Class<?> parent = type.getSuperclass(); if (parent == Object.class) { return false; } if (parent.getClass() == hasParentType.getClass()) { return true; } return checkAllParents(parent, hasParentType); } 

     Set<Class<?>> s = loadClasses("package2").stream() .filter(i->checkAllParents(i, SuperClass.class)) .collect(Collectors.toSet()); 
    • "package1" is generally unknown. Apparently only brute force handles ... - pegoopik
    • "The reason is that the ChildClass class is not a direct descendant of SuperClass but through the ParentClass class" is not the answer. This is a consequence of the reasoning in the "question". Yes, I noticed it, and why is this happening? - pegoopik
    • This is because Reflections does not go recursively to check "parents-parents", etc., and why it does not go away is the implementation of Reflections (see the source). Look in the direction of the class's getSuperclass class. If calling it recursively throughout the inheritance hierarchy, it will work as it should. - Mikhailov Valentine
    • Already looked. I answered the answer. But can you add this information in response? - pegoopik