2012-09-19 21 views
4

继续发布此处的问题:Can you find all classes in a package using reflection?我开始使用反射库来查找给定类型的子类的所有类。源代码看起来像这样,从一个问题的链接SO问题:Java的思考库:查找包中的所有类

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

然而,东北角使用此代码一段时间后,我才发现,原来它只会发现,子类中的另一类型类这个包。它不会找到从其他用户定义的软件包中派生出的从外部定义的类的子类的类。

我不知道如何解决这个使用反射库。我希望所有将它们的包声明为'org.somepackage'的类,而不管它们的超类是什么。任何帮助?

回答

6

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

import gigadot.exp.reflects.core.Processor; 

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

但是你应该小心,因为在classpath中搜索所有东西是一个缓慢的过程。

这个库比Reflections简单得多,可能不会做你想做的。我提交错误报告时,由于我的沮丧,我写了这些,但没有人尝试解决问题。

+0

这看起来很有希望。我不需要执行很多这样的调用,但是它们完全详尽至关重要。谢谢你,我会研究这个。 – mtrc

+1

编辑 - 是否在任何地方列出Rebound的依赖关系,例如log4j的? – mtrc

+0

对,得到这个工作 - 完全按照需要工作。感谢你这样做,你真的保存了一天。我现在可以回家了! – mtrc

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

这样做的原因是,

ref.getSubtypesOf(Object.class); 

只返回对象的直接子类。如果你想从一个扫描包得到所有的类,你应该做到以下几点:

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

希望有所帮助。

+0

不知道为什么没有人对这种方法进行过尝试/反馈,它对我来说效果很好。谢谢! – juanmf

+0

'HashSet > classes'为空(不知道为什么),但'Set typeSet'包含正确的类名。 – juanmf