2013-04-09 14 views
10

Sto cercando un modo per elencare tutti i pacchetti secondari di un pacchetto arbitrario in Java.Elenca tutti i sottopacchetti di un pacchetto

Qualcosa di simile a questo:

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

C'è un modo per farlo? Grazie in anticipo.

Come fa IDE (diciamo Netbeans) farlo? enter image description here

UPDATE:

sto cercando di trovare tutto il pacchetto mapper per MyBatis. Nel mio progetto, tutti i pacchetti dei mappatori devono nominare "* .mappers". Ad esempio: "a.b.mappers" o "a.b.c.mappers". Il fatto è che conosco solo il pacchetto di base e non sono sicuro di quanti pacchetti di mapping ci sono sotto.

UPDATE: Ecco il mio codice cercando di utilizzare libreria di riflessione per farlo:

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

Non capisco perché questo non funziona. Nessuna classe si trova qui ....

UPDATE

Ecco il mio codice per farlo. Un po 'lento, ma la prestazione non è quella grande preoccupazione nel mio caso. Non ho mai usato la primavera prima, quindi se ci sono modi migliori per farlo, fammi sapere. Grazie.

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

maggior parte del codice viene copiato da How do I read all classes from a Java package in the classpath?

+1

hai visto questo: http://stackoverflow.com/questions/4212088/java-programmatically-determine-all-of-the-package-names-loaded-on-the-classpa – Azodious

risposta

0

1) Caricare qualsiasi classe dal pacchetto e ottenere il relativo URL

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

2) Determinare se si tratta di un file o vaso.

2) utilizzare File.list() per la directory o JarFile.getEntries per vaso di trovare sottopackage

+0

... questo presuppone tutto delle altre classi nel pacchetto si trovano nello stesso barattolo (corretto al 99% del tempo, ma comunque ..) – radai

+0

Questo dovrebbe anche essere eseguito in modo diverso nelle esecuzioni di test Maven, poiché Maven aggiunge il codice di test compilato solo quando è nell'esecuzione in ambito di test. Naturalmente, non ci sono connessioni tra pacchetti e sotto pacchetti, quindi questa attività sembra un po 'strana. –

+0

@Evgeniy Dorofeev come si determina se questo URL è un file o un jar. Grazie. – Xin

6

Suppongo che il modo più semplice per ottenere i pacchetti è quello di ottenere tutti i pacchetti della vostra classe loader con

Package.getPackages() 

e filtrare con il tuo nome pacchetto con

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

Grande consiglio! Sto lavorando con un progetto che non può avere più dipendenze e questa è una soluzione veramente buona e leggera, anche se non l'ho ancora usata. – gustavohenke

+0

Come indicato su http://stackoverflow.com/a/13944677/421602, questo fornisce tutti i pacchetti noti (!) All'attuale caricatore di classe, quindi se non hai ancora effettuato l'accesso a una classe in un determinato pacchetto, ha vinto far parte di questa lista – vorburger

0

Un altro possibile modo per risolvere questo problema sarebbe quella di utilizzare il programma di caricamento classe sistema per caricare tutti i barattoli/file zip in il classpath e poi semplicemente ispezionarli.

Le prestazioni non saranno eccezionali. Perché stiamo ispezionando i file jar/zip, ma funziona.

Ecco qualche esempio di codice:

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

Questa uscita qualcosa vi piacerà:

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

Elaborare: IDE in realtà leggere i file JAR delle dipendenze.Nel file JAR è solo una struttura di directory. Questo è diverso dal modo in cui Java ClassLoader lo memorizza.

Problemi correlati