12

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

像这样的东西:

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

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

IDE(比方说 Netbeans)是如何做到的? 在此处输入图像描述

更新:

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

更新:这是我尝试使用反射库的代码:

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

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

更新

这是我的代码。有点慢,但就我而言,性能并不是那么大的问题。我以前从未使用过 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));
    }

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

4

4 回答 4

10

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

Package.getPackages()

并用你的包名过滤它

packageName.startsWith("com.yourcompany.yourpackage")
于 2014-01-18T08:42:04.830 回答
0

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

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

2)判断是文件还是jar。

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

于 2013-04-09T04:28:27.163 回答
0

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

于 2018-02-28T09:30:25.277 回答
0

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

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

这是一些示例代码:

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

这将输出如下内容:

com.fasterxml
com.fasterxml.jackson
com.fasterxml.jackson.annotation
com.fasterxml.jackson.core
com.fasterxml.jackson.core.base
com.fasterxml.jackson.core.filter
com.fasterxml.jackson.core.format
com.fasterxml.jackson.core.io
com.fasterxml.jackson.core.json
com.fasterxml.jackson.core.sym
com.fasterxml.jackson.core.type
com.fasterxml.jackson.core.util
com.fasterxml.jackson.databind
com.fasterxml.jackson.databind.annotation
com.fasterxml.jackson.databind.cfg
com.fasterxml.jackson.databind.deser
com.fasterxml.jackson.databind.deser.impl
com.fasterxml.jackson.databind.deser.std
com.fasterxml.jackson.databind.exc
...
于 2017-05-02T15:44:39.680 回答