2009-07-20 8 views

Répondre

10

Vous ne pouvez pas. Les classes peuvent entrer par l'intermédiaire de plusieurs chargeurs de classe différents, y compris ceux à distance.

1

Il n'existe pas de méthode globale pour cela. Cela dit, si vous savez d'où proviennent vos classes, vous pouvez parcourir le répertoire d'un fichier jar ou le système de fichiers.

3

Il y a un extrait de here qui fait exactement ce que vous voulez, en supposant les classes peut être trouvée localement :

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

Est-ce que cela fonctionne avec les classes jar'ed? –

+0

Autant que je peux dire que cela échouera si vous avez un jar (-1), mais est une routine décente pour rechercher des fichiers .class pour la découverte (+1) afin que vous atteignez l'équilibre :) –

+0

Le code ci-dessus suppose non seulement que les classes du package donné sont locales, mais aussi qu'elles ont toutes été chargées par le même chargeur de classe ET qu'elles n'ont pas été empaquetées. – ChssPly76

1

Java n'a pas découverte. La plupart des produits qui ont la capacité d'ajouter (découvrir) de nouvelles classes ont un fichier texte décrivant "Program Extensions" ou un répertoire spécifique où vous pouvez placer des classes ou des jars qui utilisent un truc comme @JG décrit. (C'est ce que fait eclipse et est recommandé pour toute solution où l'utilisateur peut ajouter le nouveau module à la main)

+1

N'oubliez pas les API SPI pour les plugins. Ceux-ci fournissent une solution raisonnablement élégante pour les frameworks de plugin. – jsight

7

Voici une façon plus complète de résoudre cela pour les pots, basée sur l'idée publiée par 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 pas de documentation ou même un indice sur ce qu'il fait, +2 car il semble qu'il scanne le classpath et inclut des bocaux! donc vous net un +1 :) –

+0

(Eh bien, il y avait un indice sur ce qu'il fait .. Je le reprends). –

+0

Ajout d'un en-tête javadoc pour une meilleure explication. :) – toluju

1

Les réponses ci-dessus décrivent les fonctionnalités requises. Cependant, plus de détails sur le sujet peuvent être trouvés here et here.