java 列出一个包的所有子包

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15893174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 21:12:08  来源:igfitidea点击:

List all subpackages of a package

javaspring

提问by Xin

I am looking for a way to list all the subpackages of an arbitrary package in Java.

我正在寻找一种方法来列出 Java 中任意包的所有子包。

Something like this:

像这样的东西:

Package basePackage = getPackage("com.mypackage");
for(Package subPackage : basepackage.getSubPackages()){
  System.out.println(subPackage.getName());
}

Is there a way to do it? Thanks in advance.

有没有办法做到这一点?提前致谢。

How does IDE(let's say Netbeans) do it? enter image description here

IDE(比如 Netbeans)是如何做到的? 在此处输入图片说明

UPDATE:

更新:

I am trying to find all the mappers package for MyBatis. In my project, all the mappers packages has to name "*.mappers". For example: "a.b.mappers" or "a.b.c.mappers". The thing is I only know the base package, and not sure how many mappers packages under it.

我正在尝试为 MyBatis 找到所有的映射器包。在我的项目中,所有映射器包都必须命名为“*.mappers”。例如:“abmappers”或“abcmappers”。问题是我只知道基本包,并且不确定它下有多少映射器包。

UPDATE: Here is my code trying to use reflection library to do it:

更新:这是我的代码尝试使用反射库来做到这一点:

private Set<String> getPackagesNames() {
    Reflections reflections = new Reflections("com.mypackage");
    Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);
    Set<String> packageNames = new HashSet<>();

    for( Iterator<Class<? extends Object>> it = allClasses.iterator(); it.hasNext(); ) {
        Class<? extends Object> subClass= it.next();
        packageNames.add(subClass.getPackage().getName());
    }

    return packageNames;
}

Not sure why this does not work. No class is found here....

不知道为什么这不起作用。这里没有找到类....

UPDATE

更新

Here is my code to do it. Kind of slow, but the performance is not that big concern in my case. I have never used Spring before, so if there are better ways to do it, let me know. Thanks.

这是我的代码。有点慢,但在我的情况下,性能并不是那么大。我以前从未使用过 Spring,所以如果有更好的方法,请告诉我。谢谢。

    private static Set<String> getPackages(String basePackage) throws IOException, ClassNotFoundException {
        Set<String> packagesNames = new HashSet<>();

        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + "**/*.class";
        Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
        for( Resource resource : resources ) {
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);    
                Class aClass = Class.forName(metadataReader.getClassMetadata().getClassName());
                String packageName = aClass.getPackage().getName();
                packagesNames.add(packageName);
            }
        }
        return packagesNames;
    }

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

Most of the code is copied from How do I read all classes from a Java package in the classpath?

大部分代码是从如何从类路径中的 Java 包中读取所有类?

回答by Dmitry Erokhin

I suppose the easiest way to get packages is to get all packages of your class loader with

我想获取包的最简单方法是获取类加载器的所有包

Package.getPackages()

and filter it with your package name with

并用你的包名过滤它

packageName.startsWith("com.yourcompany.yourpackage")

回答by gil.fernandes

Another possible way of solving this problem would be to use the system classloader to load all jars / zip files in the classpath and then simply inspect these.

解决此问题的另一种可能方法是使用系统类加载器加载类路径中的所有 jars/zip 文件,然后简单地检查它们。

Performance will not be great. Because we are inspecting jar / zip files, but it works.

性能不会很好。因为我们正在检查 jar / zip 文件,但它有效。

Here is some example code:

下面是一些示例代码:

import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.JarInputStream;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;

public class ClasspathLister {

    public static void main(String[] args) {
        listPackages("com/fasterxml").forEach(s -> {
            System.out.printf("%s%n", s.replace("/", ".").replaceAll("\.$", ""));
        });
    }

    private static Set<String> listPackages(String prefix) {
        URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        return Arrays.stream(sysloader.getURLs())
            .filter(u -> u.toString().matches("(?i).+(\.jar|\.zip)$"))
            .flatMap(u -> listJar(u, prefix).stream())
            .collect(Collectors.toCollection(TreeSet::new));
    }

    private static Set<String> listJar(URL u, String prefix) {
        Set<String> packages = new LinkedHashSet<>();
        try (JarInputStream in = 
            new JarInputStream(Files.newInputStream(Paths.get(u.toURI())))) {
            ZipEntry ze;
            while ((ze = in.getNextEntry()) != null) {
                if (ze.isDirectory() && ze.getName().startsWith(prefix)) {
                    packages.add(ze.getName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return packages;
    }
}

This will output something like:

这将输出如下内容:

com.fasterxml
com.fasterxml.Hymanson
com.fasterxml.Hymanson.annotation
com.fasterxml.Hymanson.core
com.fasterxml.Hymanson.core.base
com.fasterxml.Hymanson.core.filter
com.fasterxml.Hymanson.core.format
com.fasterxml.Hymanson.core.io
com.fasterxml.Hymanson.core.json
com.fasterxml.Hymanson.core.sym
com.fasterxml.Hymanson.core.type
com.fasterxml.Hymanson.core.util
com.fasterxml.Hymanson.databind
com.fasterxml.Hymanson.databind.annotation
com.fasterxml.Hymanson.databind.cfg
com.fasterxml.Hymanson.databind.deser
com.fasterxml.Hymanson.databind.deser.impl
com.fasterxml.Hymanson.databind.deser.std
com.fasterxml.Hymanson.databind.exc
...

回答by Simon Baars

To elaborate: IDE's actually read the JAR files of the dependencies. In the JAR file it's just a directory structure. This is different from the way the Java ClassLoader stores it.

详细说明:IDE实际上读取了依赖项的JAR文件。在 JAR 文件中,它只是一个目录结构。这与 Java ClassLoader 存储它的方式不同。

回答by Evgeniy Dorofeev

1) Load any class from the package and get its URL

1) 从包中加载任何类并获取其 URL

URL u = Test.class.getResource("");

2) Determine if it is a file or jar.

2) 判断是文件还是jar。

2) use File.list() for directory or JarFile.getEntries for jar to find subpackages

2) 使用 File.list() 作为目录或使用 JarFile.getEntries 作为 jar 来查找子包