Thinking lib for Java:查找包中的所有类

时间:2012-09-19 16:12:06

标签: java reflection

继这里发布的问题:Can you find all classes in a package using reflection?我开始使用Reflections库来查找子类给定类型的所有类。源代码看起来像这样,来自对链接的SO问题的回答:

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);

然而,在暂时使用这段代码之后,我刚刚发现它只会找到在这个包中继承另一种类型的类。它不会找到子类外部定义类的类,比如来自另一个用户定义的类。

我不知道如何使用Reflections库解决这个问题。我希望所有将其包声明为'org.somepackage'的类,无论它们的超类型是什么。有什么帮助吗?

3 个答案:

答案 0 :(得分:6)

我编写了一个名为Rebound的库(与Reflection相对),它搜索给定类型和包前缀的子类。如果将前缀设置为空,它将搜索类路径下的每个类,例如

import gigadot.exp.reflects.core.Processor;

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

但是你应该小心,因为在类路径中搜索所有内容都是一个缓慢的过程。

图书馆比思考简单得多,可能不会做你想要的。我写这篇文章是因为我在提交错误报告时感到沮丧,但没有人试图解决问题。

答案 1 :(得分:2)

原因是,

ref.getSubtypesOf(Object.class);

只返回Object的直接子类。如果要从扫描包中获取所有类,则应执行以下操作:

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()));

这可能看起来有点hackish,但这是我到目前为止找到的唯一方法。 以下是对此的解释: 当使用扫描完成“反射”时,它会将所有元素放在多值映射中。在我粘贴的代码示例中,结果使用以下键放在地图中:

SubTypesScanner, ResourcesScanner, TypeElementsScanner

ResourceScanner排除以.class结尾的所有文件。 TypeElementsScanner是一个带有键的映射,其中包含类的名称和字段的值等。因此,如果您只想获取类名,则基本上可以获取键集,稍后将其转换为集合,如果类。 SubTypesScanner也是一个映射,包含所有超类(包括对象和接口)和值的键 - 实现/扩展这些接口/类的类。

如果您愿意,也可以通过迭代键集并获取所有值来使用SubTypesScanner,但如果某个类实现了接口,则必须处理重复的实体(因为每个类都扩展了Object)。

希望有所帮助。

答案 2 :(得分:0)

就我而言,此代码可以正常加载外部API的类,但不确定为什么它不适用于像'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"))));