vancetang / reflections

Automatically exported from code.google.com/p/reflections
Do What The F*ck You Want To Public License
0 stars 0 forks source link

SubTypesScanner only looks at immediate superclass and implemented interfaces #177

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Consider the following inheritance hierarchy:
class C extends abstract class B implements interface A
class D implements interface A
2. We want to find all classes that implement A
3. Execute the following code:
Reflections reflections = new Reflections("some.package");
reflections.getSubTypesOf(A.class);

What is the expected output? What do you see instead?
Expected:
B, C, D

Actual:
B, D

What version of the product are you using? On what operating system?
0.9.9-RC1, Windows 7

Please provide any additional information below.
This is more of an enhancement request than a defect. But it would be nice if 
there was a way to find subtypes of a class or interface that are more than one 
level down in the inheritance hierarchy. I wrote a custom scanner that allows 
me to do this. As it is written, it will only work with JavaReflectionAdapter.

import java.util.List;

import org.reflections.ReflectionUtils;
import org.reflections.scanners.SubTypesScanner;

/**
 * Custom scanner implementation. Required since SubTypesScanner only looks at the 
 * immediate superclass and interfaces. This scanner will recursively traverse the 
 * inheritance hierarchy, allowing you to find subtypes many levels from the class
 * or interface you use as your search key.
 */
public class DeepSubTypesScanner extends SubTypesScanner {

    public DeepSubTypesScanner() {
        super(true); // exclude direct Object subtypes by default
    }

    public DeepSubTypesScanner(boolean excludeObjectClass) {
        super(excludeObjectClass);
    }

    @SuppressWarnings({ "unchecked" })
    public void scan(final Object cls) {
        String className = getMetadataAdapter().getClassName(cls);
        scanRecursive(cls, className);
    }

    @SuppressWarnings({ "unchecked" })
    public void scanRecursive(final Object cls, String className) {
        String superClassName = getMetadataAdapter().getSuperclassName(cls);

        if (acceptResult(superClassName)) {
            getStore().put(superClassName, className);
            scanRecursive(ReflectionUtils.forName(superClassName), className);
        }

        for (String anInterface : (List<String>) getMetadataAdapter().getInterfacesNames(cls)) {
            if (acceptResult(anInterface)) {
                getStore().put(anInterface, className);
            }
        }
    }
}

Usage:
        Reflections reflections = new Reflections(new ConfigurationBuilder()
                                                        .setUrls(ClasspathHelper.forPackage("some.package"))
                                                        .setScanners(new DeepSubTypesScanner())
                                                        .setMetadataAdapter(new JavaReflectionAdapter()));

        Set<String> subTypes = reflections.getStore().get(DeepSubTypesScanner.class, A.class);
        Set<Class<? extends T>> classes = Sets.newHashSet(ReflectionUtils.<T>forNames(subTypes));

Original issue reported on code.google.com by jeff.hal...@gmail.com on 4 Jun 2014 at 7:26

GoogleCodeExporter commented 9 years ago
This works as expected. Just make sure you scan _all_ the relevant root 
packages (does C matches "some.package"?) - new Reflections("some.package", 
"another.package", ...)

Original comment by ronm...@gmail.com on 5 Jun 2014 at 5:36

GoogleCodeExporter commented 9 years ago

Original comment by ronm...@gmail.com on 5 Jun 2014 at 6:23

GoogleCodeExporter commented 9 years ago
Ah yes you are right! That solved the issue! Thanks a lot for your very prompt 
response! 

Original comment by jeff.hal...@gmail.com on 5 Jun 2014 at 1:11