2013-04-09 69 views
10

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

事情是这样的:

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

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

IDE(比方说Netbeans)如何做到这一点? enter image description here

UPDATE:

我试图找到所有映射器包MyBatis的。在我的项目中,所有的mappers软件包都必须命名为“* .mappers”。例如:“a.b.mappers”或“a.b.c.mappers”。事情是我只知道基础包,不知道它下面有多少个映射器包。

UPDATE: 这里是我的代码试图利用反射库来做到这一点:

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

不知道为什么,这是行不通的。无级在这里找到....

UPDATE

这里是我的代码来做到这一点。有点慢,但在我的情况下,表现并不是那么重要。我之前从未使用过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)); 
    } 

大部分代码是从How do I read all classes from a Java package in the classpath?

+1

你有没有看到这个:http://stackoverflow.com/questions/4212088/java-programmatically-determine-all-of-the-package-names-loaded-on-the-classpa – Azodious 2013-04-09 04:17:23

回答

0

1)复制从包中加载任何类,并得到其URL

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

2)确定它是否是一个文件或罐子。

2)使用的File.List()的目录或JarFile.getEntries的罐子里找到子包

+0

......这个假设都是的其他类在同一个jar中(正确率为99%,但仍然...) – radai 2013-04-09 04:30:42

+0

在Maven测试运行中,这也会以不同方式运行,因为Maven仅在测试范围中运行时才添加编译的测试代码。当然,软件包和子软件包之间没有联系,所以这个任务似乎有点奇怪。 – 2013-04-09 04:43:28

+0

@Evgeniy Dorofeev你如何确定这个URL是一个文件还是jar。谢谢。 – Xin 2013-04-09 06:25:40

6

我想拿到包的最简单的方法是让你的类加载器的所有软件包与

Package.getPackages() 

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

好的提示!我正在处理一个不能有更多依赖的项目,这是一个非常好的轻量级解决方案,尽管我还没有使用它。 – gustavohenke 2014-10-23 12:29:00

+0

正如http://stackoverflow.com/a/13944677/421602中所述,这会为您提供所有已知(!)包到当前类加载器 - 所以如果您尚未访问给定包中的类,它会赢得不属于这份名单。 – vorburger 2016-12-17 00:53:01

0

与你的包名过滤它解决这一问题的办法是使用系统类加载器加载所有jar包/ 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 
... 
0

要阐述:IDE的实际阅读依赖的JAR文件。在JAR文件中它只是一个目录结构。这与Java ClassLoader存储它的方式不同。

相关问题