2013-04-09 129 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存儲它的方式不同。