2013-04-09 19 views
10

Ich suche nach einer Möglichkeit, alle Unterpakete eines beliebigen Pakets in Java aufzulisten.Alle Unterpakete eines Pakets auflisten

Etwas wie folgt aus:

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

Gibt es eine Möglichkeit, es zu tun? Danke im Voraus.

Wie macht IDE (sagen wir Netbeans) es? enter image description here

UPDATE:

Ich versuche, alle Mapper-Paket für Mybatis zu finden. In meinem Projekt müssen alle Mapper-Pakete "* .mappers" heißen. Zum Beispiel: "a.b.mappers" oder "a.b.c.mappers". Die Sache ist, ich kenne nur das Basispaket und nicht sicher, wie viele Mapper-Pakete darunter liegen.

UPDATE: Hier ist mein Code versucht Reflexion Bibliothek zu verwenden, es zu tun:

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

nicht sicher, warum dies nicht funktioniert. Keine Klasse wird hier ....

UPDATE

Hier ist mein Code, es zu tun. Irgendwie langsam, aber die Leistung ist in meinem Fall nicht so wichtig. Ich habe den Frühling noch nie vorher benutzt, also wenn es bessere Möglichkeiten gibt, lass es mich wissen. Vielen Dank.

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

Der meiste Code wird von How do I read all classes from a Java package in the classpath? kopiert

+1

hast du dies: http://stackoverflow.com/questions/4212088/java-programmatically-determine-all-of-the-package-names-loaded-on-the-classpa – Azodious

Antwort

0

1) Laden Sie eine beliebige Klasse aus dem Paket und die entsprechende URL erhalten

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

2) fest, ob es sich um eine Datei oder ein Glas ist.

2) verwenden File.list() für das Verzeichnis oder JarFile.getEntries für jar Subpackages

+0

... dies setzt voraus, alle der anderen Klassen im Paket befinden sich im gleichen Jar (korrekt 99% der Zeit, aber immer noch ..) – radai

+0

Das würde auch anders in Maven Testläufe laufen, wie Maven fügt den kompilierten Testcode nur im Testbereich. Natürlich gibt es keine Verbindungen zwischen Paketen und Unterpaketen, daher scheint diese Aufgabe ein wenig seltsam zu sein. –

+0

@Evgeniy Dorofeev Wie ermitteln Sie, ob diese URL eine Datei oder ein Jar ist. Vielen Dank. – Xin

6

ich zu finden nehme an, der einfachste Weg, Pakete zu bekommen ist, alle Pakete Ihrer Klassenlader bekommen mit

Package.getPackages() 

und filtern es mit Ihrem Paketnamen mit

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

Toller Tipp! Ich arbeite mit einem Projekt, das nicht mehr Abhängigkeiten haben kann und das ist eine wirklich gute, leichtgewichtige Lösung, obwohl ich sie bisher noch nicht benutzt habe. – gustavohenke

+0

Wie auf http://stackoverflow.com/a/13944677/421602 beschrieben, erhalten Sie alle Pakete, die dem aktuellen Klassenlader bekannt sind (!) - wenn Sie also noch nicht auf eine Klasse in einem bestimmten Paket zugegriffen haben, hat sie gewonnen Gehört nicht zu dieser Liste. – vorburger

0

Eine weitere Möglichkeit, dieses Problem zu lösen, wäre das System Classloader zu verwenden, um alle Gläser/zip-Dateien zu laden in den Klassenpfad und dann einfach diese überprüfen.

Die Leistung wird nicht gut sein. Weil wir jar/zip-Dateien untersuchen, aber es funktioniert. Hier

ist einige Beispiel-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; 
    } 
} 

Dies wird Ausgang so etwas wie:

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

Um dies näher auszuführen: IDE tatsächlich die JAR-Dateien der Abhängigkeiten lesen.In der JAR-Datei ist es nur eine Verzeichnisstruktur. Dies unterscheidet sich von der Art, wie der Java ClassLoader es speichert.

Verwandte Themen