简体   繁体   English

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

[英]Reflections lib for Java: find all classes in a package

Further to the question posted here: Can you find all classes in a package using reflection? 继这里发布的问题: 你能用反射找到包中的所有类吗? I started using the Reflections library to find all classes that subclass a given type. 我开始使用Reflections库来查找子类给定类型的所有类。 The source code looks like this, from an answer to the linked SO question: 从链接的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);

However, after using this code obliviously for a while, I've just discovered that it will only find classes that subclass another type within this package. 然而,在暂时使用这段代码之后,我刚刚发现它只会在这个包中找到继承其他类型的类。 It won't find classes that subclass externally defined classes, say from another user-defined package. 它不会找到从外部定义的类子类化的类,比如来自另一个用户定义的类。

I'm not sure how to get around this using the Reflections library. 我不知道如何使用Reflections库来解决这个问题。 I want all classes that declare their package as 'org.somepackage', regardless of what their supertype is. 我希望所有将其包声明为'org.somepackage'的类,无论它们的超类型是什么。 Any help? 有帮助吗?

I wrote a library called Rebound (as opposed to Reflections) which searches for the subclasses of a given type and package prefix. 我写了一个名为Rebound (而不是Reflection)的库,它搜索给定类型和包前缀的子类。 If you set the prefix empty, it will search every class under the classpath, eg 如果将前缀设置为空,它将搜索类路径下的每个类,例如

import gigadot.exp.reflects.core.Processor;

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

But you should be careful, because searching everything in the classpath is a slow process. 但是你应该小心,因为在类路径中搜索所有内容是一个缓慢的过程。

The library is much simpler than Reflections and might not do what you want. 该库比Reflection简单得多,可能无法满足您的需求。 I wrote this due to my frustration when I submitted my bug report but no one there tries to solve the problem. 我写这篇文章是因为我在提交错误报告时感到沮丧,但没有人试图解决问题。

The reason for this is, that 原因是,那

ref.getSubtypesOf(Object.class);

only returns the direct subclasses of Object. 只返回Object的直接子类。 If you want to get all the classes from a scanned package, you should do the following: 如果要从扫描包中获取所有类,则应执行以下操作:

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

This may look a little hackish but it's the only way I found so far. 这可能看起来有点hackish但是这是我到目前为止找到的唯一方法。 Here's a little explanation of what this does: When Reflections is done with the scanning, it puts all the elements in a multi-value map. 以下是对此操作的一点解释:当使用扫描完成反射时,它会将所有元素放在多值映射中。 In the code example that I pasted, the results are put inside a map with the following keys: 在我粘贴的代码示例中,结果使用以下键放在地图中:

SubTypesScanner, ResourcesScanner, TypeElementsScanner

The ResourceScanner excludes all files ending with .class. ResourceScanner排除以.class结尾的所有文件。 The TypeElementsScanner is a map with a key holding the name of a class, and a value of the fields etc. So if you want to get only the class names, you basically get the key set and later on, convert it to a set if classes. TypeElementsScanner是一个带有键的映射,其中包含类的名称和字段的值等。因此,如果您只想获取类名,则基本上可以获取键集,稍后将其转换为集合,如果类。 The SubTypesScanner is also a map, with a key of all the super classes (including Object and interfaces) and values - the classes implementing/extending those interfaces/classes. SubTypesScanner也是一个映射,具有所有超类(包括对象和接口)和值的键 - 实现/扩展这些接口/类的类。

You can also use the SubTypesScanner if you wish, by iterating the keyset and getting all the values, but if a certain class implements an interface, you will have to deal with duplicate entities (as every class extends Object). 如果您愿意,也可以通过迭代键集并获取所有值来使用SubTypesScanner,但如果某个类实现了接口,则必须处理重复的实体(因为每个类都扩展了Object)。

Hope that helps. 希望有所帮助。

In my case, this code works fine to load the classes of an external API, but not sure why it does not work for a built-in package like 'java.util'. 在我的例子中,这个代码可以很好地加载外部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"))));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM