继这里发布的问题: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'的类,无论它们的超类型是什么。有什么帮助吗?
答案 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"))));