如何在类路径中读取Java包中的所有类?

93 java reflection

我需要读取Java包中包含的类.这些类在classpath中.我需要直接从Java程序执行此任务.你知道一个简单的方法吗?

List<Class> classes = readClassesFrom("my.package")
Run Code Online (Sandbox Code Playgroud)

Sha*_*938 48

如果你在类路径中有Spring,那么下面将会这样做.

查找使用XmlRootElement注释的包中的所有类:

private List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

    List<Class> candidates = new ArrayList<Class>();
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                               resolveBasePackage(basePackage) + "/" + "**/*.class";
    Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
    for (Resource resource : resources) {
        if (resource.isReadable()) {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            if (isCandidate(metadataReader)) {
                candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
            }
        }
    }
    return candidates;
}

private String resolveBasePackage(String basePackage) {
    return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}

private boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
    try {
        Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
        if (c.getAnnotation(XmlRootElement.class) != null) {
            return true;
        }
    }
    catch(Throwable e){
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)


Ren*_*ato 29

您可以使用此处描述的Reflections项目

它非常完整且易于使用.

以上网站的简要说明:

Reflections会扫描您的类路径,索引元数据,允许您在运行时查询它,并可以为项目中的许多模块保存和收集该信息.

例:

Reflections reflections = new Reflections(
    new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);
Run Code Online (Sandbox Code Playgroud)


小智 27

我使用这个,它适用于文件或jar档案

public static ArrayList<String>getClassNamesFromPackage(String packageName) throws IOException{
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL packageURL;
    ArrayList<String> names = new ArrayList<String>();;

    packageName = packageName.replace(".", "/");
    packageURL = classLoader.getResource(packageName);

    if(packageURL.getProtocol().equals("jar")){
        String jarFileName;
        JarFile jf ;
        Enumeration<JarEntry> jarEntries;
        String entryName;

        // build jar file name, then loop through zipped entries
        jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
        jarFileName = jarFileName.substring(5,jarFileName.indexOf("!"));
        System.out.println(">"+jarFileName);
        jf = new JarFile(jarFileName);
        jarEntries = jf.entries();
        while(jarEntries.hasMoreElements()){
            entryName = jarEntries.nextElement().getName();
            if(entryName.startsWith(packageName) && entryName.length()>packageName.length()+5){
                entryName = entryName.substring(packageName.length(),entryName.lastIndexOf('.'));
                names.add(entryName);
            }
        }

    // loop through files in classpath
    }else{
    URI uri = new URI(packageURL.toString());
    File folder = new File(uri.getPath());
        // won't work with path which contains blank (%20)
        // File folder = new File(packageURL.getFile()); 
        File[] contenuti = folder.listFiles();
        String entryName;
        for(File actual: contenuti){
            entryName = actual.getName();
            entryName = entryName.substring(0, entryName.lastIndexOf('.'));
            names.add(entryName);
        }
    }
    return names;
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ood 11

Spring已经实现了一个出色的类路径搜索功能PathMatchingResourcePatternResolver.如果使用classpath*:前缀,则可以找到所有资源,包括给定层次结构中的类,甚至可以根据需要过滤它们.然后,您可以使用它们的子级AbstractTypeHierarchyTraversingFilter,AnnotationTypeFilterAssignableTypeFilter在类级别注释或它们实现的接口上过滤这些资源.


Luk*_*son 7

当前列出给定包中所有类的最强大的机制是ClassGraph,因为它处理尽可能广泛的类路径规范机制,包括新的 JPMS 模块系统。(我是作者。)

List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
        .enableClassInfo().scan()) {
    classNames = scanResult.getAllClasses().getNames();
}
Run Code Online (Sandbox Code Playgroud)


小智 6

Java 1.6.0_24:

public static File[] getPackageContent(String packageName) throws IOException{
    ArrayList<File> list = new ArrayList<File>();
    Enumeration<URL> urls = Thread.currentThread().getContextClassLoader()
                            .getResources(packageName);
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        File dir = new File(url.getFile());
        for (File f : dir.listFiles()) {
            list.add(f);
        }
    }
    return list.toArray(new File[]{});
}
Run Code Online (Sandbox Code Playgroud)

此解决方案在EJB环境中进行了测试.

  • 您的代码不适用于jar中包含的资源. (5认同)

Sła*_*wek 6

ScannotationReflections使用类路径扫描方法:

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

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

Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");
Run Code Online (Sandbox Code Playgroud)


Bre*_*ode 2

据我所知,Java 反射 API 仍然可疑地缺少该功能。您可以通过执行以下操作来获取包对象:

Package packageObj = Package.getPackage("my.package");
Run Code Online (Sandbox Code Playgroud)

但正如您可能注意到的那样,这不会让您列出该包中的类。截至目前,您必须采取一种更加面向文件系统的方法。

我在这篇文章 中找到了一些示例实现

当您的类隐藏在 JAR 文件中时,我不能 100% 确定这些方法是否有效,但我希望其中一种方法可以为您提供帮助。

我同意@skaffman...如果你有另一种方法来解决这个问题,我建议你这样做。

  • 这并不可疑,只是行不通。类不“属于”包,它们有对包的引用。该关联并不指向另一个方向。 (4认同)

归档时间:

查看次数:

107895 次

最近记录:

6 年 前