2010-11-18 23 views
10

Toute suggestion quant à la façon d'aborder la façon dont je trouverais une liste de noms de paquets qui existent sur le chemin de classe actuelle ?Java: déterminer par programme tous les noms de paquets chargés sur le classpath

Cette opération doit être effectuée par programmation au moment de l'exécution par l'une des classes chargées (et exécutées) sur le chemin de classe (c'est-à-dire à l'intérieur de, pas à l'extérieur de).


Plus de détails:

Une approche que je considérais était d'utiliser la réflexion sur chacune des classes chargées jusqu'ici par le chargeur de classe, et extraire les noms de paquets d'eux. Cependant, mon application fonctionne déjà dans des milliers de classes, j'ai donc besoin d'une approche plus efficace.

Une autre chose que j'ai considérée était quelque chose d'analogue à la découverte des fichiers JAR dans le chemin de la classe, puis de faire la liste des répertoires en parallèle pour chaque fichier JAR. Cependant, je ne sais pas si cela est possible à partir de l'application/comment le faire.

points bonus

points de bonus pour tous ceux qui suggère une manière qui peut filtrer les paquets de haut niveau. Par exemple. montrer tous les paquets qui viennent sous com.xyz ==>com.xyz.*, com.xyz.*.*

Merci!

Répondre

6

Si vous avez besoin de monter et d'analyser des fichiers jar, cela a été intégré dans commons-vfs. Cela peut vous faciliter la vie si vous devez suivre cette route.

EDIT # 1: Vous pouvez obtenir le classpath comme si (l'exemple here):

String strClassPath = System.getProperty("java.class.path"); 
System.out.println("Classpath is " + strClassPath); 

De là, vous pouvez regarder les classes de système de fichiers local, pots, etc.

EDIT # 2: Voici une solution VFS:

import java.util.HashSet; 

import org.apache.commons.lang.StringUtils; 
import org.apache.commons.vfs.FileObject; 
import org.apache.commons.vfs.FileSystemManager; 
import org.apache.commons.vfs.FileType; 
import org.apache.commons.vfs.VFS; 

public class PackageLister { 

    private static HashSet<String> packageNames = new HashSet<String>(); 
    private static String localFilePath; 

    /** 
    * @param args 
    * @throws Throwable 
    */ 
    public static void main(final String[] args) throws Throwable { 
     FileSystemManager fileSystemManager = VFS.getManager(); 

     String[] pathElements = System.getProperty("java.class.path").split(";"); 
     for(String element : pathElements) { 
      if (element.endsWith("jar")) { 
       FileObject fileObject = fileSystemManager.resolveFile("jar://" + element); 
       addPackages(fileObject); 
      } 
      else { 
       FileObject fileObject = fileSystemManager.resolveFile(element); 
       localFilePath = fileObject.getName().getPath(); 

       addPackages(fileObject); 
      } 
     } 

     for(String name : packageNames) { 
      System.out.println(name); 
     } 
    } 

    private static void addPackages(final FileObject fileObject) throws Throwable { 
     FileObject[] children = fileObject.getChildren(); 
     for(FileObject child : children) { 
      if (!child.getName().getBaseName().equals("META-INF")) { 
       if (child.getType() == FileType.FOLDER) { 
        addPackages(child); 
       } 
       else if (child.getName().getExtension().equals("class")) { 
        String parentPath = child.getParent().getName().getPath(); 
        parentPath = StringUtils.remove(parentPath, localFilePath); 
        parentPath = StringUtils.removeStart(parentPath, "/"); 
        parentPath = parentPath.replaceAll("/", "."); 

        packageNames.add(parentPath); 
       } 
      } 
     } 
    } 
} 
+0

Je connais VFS mais je ne connaissais pas cette fonctionnalité. Pourriez-vous s'il vous plaît donner un conseil quelle classe aide à scanner le classpath? – AlexR

3

Donnez http://code.google.com/p/reflections/ un coup de feu.

Réflexions scanne votre classpath, index des métadonnées, vous permet de requête sur l'exécution et peut enregistrer et recueillir cette information pour de nombreux modules dans votre projet.

2

Ce code vous donnera toutes les classpath-entrées (y compris les bibliothèques jre):

String[] entries = ClassPath.getClassPath().split(";"); 
for (String entry:entries) 
    System.out.println(entry); 

ClassPath fait partie de apache bcel et se trouve comme une classe interne (mais utilisable) dans le jre (com.sun.org.apache.bcel.internal.util). AFAIK, la classe est "interne" pour éviter les conflits lorsqu'un projet nécessite la "vraie" bibliothèque bcel.

Vous pouvez filtrer les bibliothèques du JRE (ils sont inclus comme cela est le vrai classpath)

L'étape suivante serait à la recherche à chaque entrée (JarFile-), visitez tous les sous-répertoires (récursivement) et si (et seulement si) un répertoire contient au moins un fichier de classe, le nom de ce répertoire (relatif à l'entrée classpath) peut être converti en un nom de paquet (exemple: META_INF est un répertoire dans tous les fichiers jar mais pas un nom de paquetage ...)