是否有可能找到给定包中的所有类或接口?(快速看了一下e.g. Package,似乎没有。)


当前回答

是的,你可以使用很少的API,这是我喜欢做的,面对这个问题,我使用hibernate核心&必须找到类,其中注释了某个注释。

使这些自定义注释使用,您将标记哪些类您想要获得。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EntityToBeScanned {

}

然后用它来标记你的课

@EntityToBeScanned 
public MyClass{

}

创建具有以下方法的实用程序类

public class ClassScanner {

    public static Set<Class<?>> allFoundClassesAnnotatedWithEntityToBeScanned(){
        Reflections reflections = new Reflections(".*");
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(EntityToBeScanned.class);
        return annotated;
    }

}

调用allfoundclassesannotatedwithentitytobescans()方法获取找到的类集。

你将需要下列的参考书目

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>21.0</version>
    </dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.22.0-CR1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>

其他回答

那么这个呢:

public static List<Class<?>> getClassesForPackage(final String pkgName) throws IOException, URISyntaxException {
    final String pkgPath = pkgName.replace('.', '/');
    final URI pkg = Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource(pkgPath)).toURI();
    final ArrayList<Class<?>> allClasses = new ArrayList<Class<?>>();

    Path root;
    if (pkg.toString().startsWith("jar:")) {
        try {
            root = FileSystems.getFileSystem(pkg).getPath(pkgPath);
        } catch (final FileSystemNotFoundException e) {
            root = FileSystems.newFileSystem(pkg, Collections.emptyMap()).getPath(pkgPath);
        }
    } else {
        root = Paths.get(pkg);
    }

    final String extension = ".class";
    try (final Stream<Path> allPaths = Files.walk(root)) {
        allPaths.filter(Files::isRegularFile).forEach(file -> {
            try {
                final String path = file.toString().replace('/', '.');
                final String name = path.substring(path.indexOf(pkgName), path.length() - extension.length());
                allClasses.add(Class.forName(name));
            } catch (final ClassNotFoundException | StringIndexOutOfBoundsException ignored) {
            }
        });
    }
    return allClasses;
}

然后你可以重载这个函数:

public static List<Class<?>> getClassesForPackage(final Package pkg) throws IOException, URISyntaxException {
    return getClassesForPackage(pkg.getName());
}

如果你需要测试:

public static void main(final String[] argv) throws IOException, URISyntaxException {
    for (final Class<?> cls : getClassesForPackage("my.package")) {
        System.out.println(cls);
    }
    for (final Class<?> cls : getClassesForPackage(MyClass.class.getPackage())) {
        System.out.println(cls);
    }
}

如果你的IDE没有导入helper:

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

工作原理:

从您的IDE JAR文件 没有外部依赖

org。反思版0.10:

org.reflections.scanners.SubTypesScanner 

and

org.reflections.Reflections.getAllTypes() 

弃用。我userd:

public Set<String> getEntityNamesInPackage(String packagePath) {
    Reflections reflections = new Reflections(new ConfigurationBuilder()
                    .filterInputsBy(new FilterBuilder().includePackage(packagePath))
                    .setUrls(ClasspathHelper.forPackage(packagePath))
                    .setScanners(SubTypes.filterResultsBy(s -> true)));

    return reflections.getAll(SubTypes).stream()
            .filter(s -> s.startsWith(packagePath))
            .collect(Collectors.toSet());
}

谷歌Guava 14包含了一个新类ClassPath,它有三个方法来扫描顶级类:

getTopLevelClasses () getTopLevelClasses(管柱packageName) getTopLevelClassesRecursive(管柱packageName)

有关更多信息,请参阅ClassPath javadocs。

在使用Maven时,Aleksander Blomskøld的解决方案对我的参数化测试@RunWith(parameterized .class)不起作用。正确命名了测试,并显示了找到但未执行的位置:

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running some.properly.named.test.run.with.maven.SomeTest
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.123 sec

这里也报道了类似的问题。

在我的例子中,@Parameters是在包中创建每个类的实例。这些测试在IDE中本地运行时运行良好。然而,当运行Maven时,在Aleksander Blomskøld的解决方案中没有找到类。

我确实用以下剪辑完成了它,灵感来自David Pärsson对Aleksander Blomskøld回答的评论:

Reflections reflections = new Reflections(new ConfigurationBuilder()
            .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
            .addUrls(ClasspathHelper.forJavaClassPath()) 
            .filterInputsBy(new FilterBuilder()
            .include(FilterBuilder.prefix(basePackage))));

Set<Class<?>> subTypesOf = reflections.getSubTypesOf(Object.class);

一般来说,类装入器不允许扫描类路径上的所有类。但通常唯一使用的类加载器是UrlClassLoader,我们可以从中检索目录和jar文件的列表(参见getURLs),并逐个打开它们以列出可用的类。这种方法称为类路径扫描,在Scannotation和Reflections中实现。

Reflections reflections = new Reflections("my.package");
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

另一种方法是使用Java可插入注释处理API编写注释处理器,该处理器将在编译时收集所有注释类,并构建索引文件供运行时使用。此机制在ClassIndex库中实现:

// package-info.java
@IndexSubclasses
package my.package;

// your code
Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");

注意,由于Java编译器自动发现类路径上的任何处理器,因此扫描是完全自动化的,因此不需要额外的设置。