2010-11-18 3 views
10

Irgendwelche Vorschläge, wie geladen bestimmen zu nähern, wie ich eine Liste von Paketnamen finden würde die auf dem aktuellen Classpath existieren?Java: programmatisch alle der Paketnamen auf dem Classpath

Dies muss programmgesteuert zur Laufzeit von einer der Klassen durchgeführt (und ausgeführt) auf dem Klassenpfad (d. H. Inside Out, nicht außerhalb in).


Weitere Details:

Ein Ansatz war ich als Reflexion auf jede der Klassen so weit von der Klassenlader geladen zu verwenden, und extrahieren daraus die Paketnamen. Meine Anwendung läuft jedoch bereits in Tausenden von Klassen, daher brauche ich einen effizienteren Ansatz.

Eine andere Sache, ich war als etwas analog zu herauszufinden, was JAR-Dateien im Klassenpfad waren, und dann tun Sie das Verzeichnis für jede JAR-Eintrag parallel. Ich weiß jedoch nicht, ob dies aus der Anwendung heraus möglich ist/wie es gemacht wird.

Bonuspunkte

Bonuspunkte für jeden, der eine Art und Weise schlägt vor, die von Top-Level-Pakete filtern. Z.B. zeige alle Pakete, die unter com.xyz kommen ==> , com.xyz.*.*

Vielen Dank!

Antwort

6

Wenn Sie JAR-Dateien mounten und scannen müssen, ist das commons-vfs eingebaut. Das könnte die Dinge ein wenig einfacher machen, wenn Sie diese Route gehen müssen.

EDIT # 1: Sie können die Classpath wie so erhalten (aus dem Beispiel here):

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

Von dort können Sie die lokalen Dateisystemklassen buchen, Gläser etc.

EDIT # 2: Hier ist eine Lösung mit 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

Ich kenne VFS aber wusste nicht über diese Funktionalität. Könnten Sie bitte einen Tipp geben, welche Klasse hilft, den Klassenpfad zu scannen? – AlexR

3

http://code.google.com/p/reflections/ ein Schuss.

Reflections sucht Ihre Classpath, Indizes die Metadaten, können Sie Abfrage auf Laufzeit und speichern kann und sammeln diese Informationen für viele Module in Ihrem Projekt. Dieser Code wird Ihnen alle Classpath-Einträge

2

(einschließlich der jre Bibliotheken):

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

ClassPath Teil von Apache bcel und kann als interne (aber brauchbar) Klasse in der jre finden (com.sun.org.apache.bcel.internal.util). AFAIK, die Klasse ist "intern", um Konflikte zu vermeiden, wenn ein Projekt die "echte" bcel-Bibliothek benötigt.

Sie können die Bibliotheken der JRE filtern möchten (sie enthalten sind, da diese die wirkliche Classpath ist)

Der nächste Schritt bei jeder (JarFile-) Eintrag würde suchen, alle Unterverzeichnisse besuchen (rekursiv) und wenn (und nur wenn) ein Verzeichnis mindestens eine Klassendatei enthält, kann der Name dieses Verzeichnisses (relativ zum Klassenpfadeintrag) in einen Paketnamen umgewandelt werden (Beispiel: META_INF ist ein Verzeichnis in allen JAR-Dateien, aber nicht ein Paketname ...)