2009-07-20 15 views

risposta

10

Non è possibile. Le classi possono venire attraverso molti caricatori di classi diverse, incluse quelle remote.

1

Non esiste un modo globale per farlo. Detto questo, se sai da dove provengono le tue lezioni, puoi percorrere la directory di un file jar o del file system.

3

C'è un frammento da here che fa esattamente quello che vuoi, assumendo le classi possono essere trovati localmente:

private static Class[] getClasses(String packageName) 
throws ClassNotFoundException, IOException { 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
    assert classLoader != null; 
    String path = packageName.replace('.', '/'); 
    Enumeration<URL> resources = classLoader.getResources(path); 
    List<File> dirs = new ArrayList<File>(); 
    while (resources.hasMoreElements()) { 
     URL resource = resources.nextElement(); 
     dirs.add(new File(resource.getFile())); 
    } 
    ArrayList<Class> classes = new ArrayList<Class>(); 
    for (File directory : dirs) { 
     classes.addAll(findClasses(directory, packageName)); 
    } 
    return classes.toArray(new Class[classes.size()]); 
} 

private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException { 
    List<Class> classes = new ArrayList<Class>(); 
    if (!directory.exists()) { 
     return classes; 
    } 
    File[] files = directory.listFiles(); 
    for (File file : files) { 
     if (file.isDirectory()) { 
      assert !file.getName().contains("."); 
      classes.addAll(findClasses(file, packageName + "." + file.getName())); 
     } else if (file.getName().endsWith(".class")) { 
      classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); 
     } 
    } 
    return classes; 
} 
+0

Funziona con le classi jar? –

+0

Per quanto posso dire questo fallirà se si dispone di un jar (-1), ma è una routine decente per la ricerca di file .class per discovery (+1) in modo da ottenere un break even :) –

+0

Il codice sopra riportato non solo presuppone che le classi dal pacchetto dato sono locali, ma anche che sono state tutte caricate dallo stesso caricatore di classe E non sono state impacchettate. – ChssPly76

1

Java non ha scoperta.

La maggior parte dei prodotti che hanno la possibilità di aggiungere (scoprire) nuove classi hanno un file di testo che descrive "Estensioni del programma" o una directory specifica in cui è possibile posizionare sia le classi che i jar che utilizza un trucco come @JG descritto. (Questo è ciò che fa Eclipse ed è raccomandato per qualsiasi soluzione in cui l'utente possa aggiungere il nuovo modulo a mano)

+1

Non dimenticare le API SPI per i plugin. Questi forniscono una soluzione ragionevolmente elegante per i framework di plugin. – jsight

7

Ecco un modo più completo per risolvere questo problema con i vasi, basato sull'idea pubblicata da JG.

/** 
* Scans all classloaders for the current thread for loaded jars, and then scans 
* each jar for the package name in question, listing all classes directly under 
* the package name in question. Assumes directory structure in jar file and class 
* package naming follow java conventions (i.e. com.example.test.MyTest would be in 
* /com/example/test/MyTest.class) 
*/ 
public Collection<Class> getClassesForPackage(String packageName) throws Exception { 
    String packagePath = packageName.replace(".", "/"); 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
    Set<URL> jarUrls = new HashSet<URL>(); 

    while (classLoader != null) { 
    if (classLoader instanceof URLClassLoader) 
     for (URL url : ((URLClassLoader) classLoader).getURLs()) 
     if (url.getFile().endsWith(".jar") // may want better way to detect jar files 
      jarUrls.add(url); 

    classLoader = classLoader.getParent(); 
    } 

    Set<Class> classes = new HashSet<Class>(); 

    for (URL url : jarUrls) { 
    JarInputStream stream = new JarInputStream(url.openStream()); // may want better way to open url connections 
    JarEntry entry = stream.getNextJarEntry(); 

    while (entry != null) { 
     String name = entry.getName(); 
     int i = name.lastIndexOf("/"); 

     if (i > 0 && name.endsWith(".class") && name.substring(0, i).equals(packagePath)) 
     classes.add(Class.forName(name.substring(0, name.length() - 6).replace("/", "."))); 

     entry = stream.getNextJarEntry(); 
    } 

    stream.close(); 
    } 

    return classes; 
} 
+0

-1 Nessuna documentazione o suggerimento su ciò che fa, +2 perché sembra che analizzi il classpath e includa i vasi! così fai net +1 :) –

+0

(Beh, c'era un indizio su quello che fa .. Lo riprendo). –

+0

Aggiunta un'intestazione javadoc per una spiegazione migliore. :) – toluju

1

Le risposte sopra illustrano la funzionalità richiesta. Tuttavia, ulteriori dettagli sull'argomento possono essere trovati here e here.

Problemi correlati