2010-08-09 147 views
0

我正在尋找一種實用方法,以便給定一個類將返回從外部運行此類所需的完整類路徑。這意味着類所在的jar以及它使用的類的所有jar(或文件夾)。從類獲取完整的類路徑

更新:有工具可以分析.class文件以查找依賴關係。這不是我要找的。我正在尋找在已經加載的類上使用Java反射API的東西。我會解決一些分析字節碼的問題,如果它遞歸地通過類加載器找到的類,則可以使用

回答

2

反射不會幫你很多這個。您將需要分析字節碼以查找依賴關係。

更新:

好吧。我正在使用多年前創建的庫,可以下載here

下面的代碼:

package classdep; 

import java.io.InputStream; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 
import org.jedo.classfile.ClassFile; 
import org.jedo.classfile.ConstantPool; 

public class Main { 

    public static void main(String[] args) { 
     try { 
      ClassLoader cl = Thread.currentThread().getContextClassLoader(); 
      List<String> classes = new ArrayList<String>(); 
      classes.add(args[0].replace('.', '/')); 
      for (int i = 0; i < classes.size(); ++i) { 
       String className = classes.get(i); 
       URL url = cl.getResource(className + ".class"); 
       if (url == null) { 
        System.out.println("--- class not found " + className); 
       } else { 
        System.out.println(url); 
        ClassFile classFile = new ClassFile(); 
        InputStream in = url.openStream(); 
        try { 
         classFile.load(in); 
        } finally { 
         in.close(); 
        } 
        ConstantPool cp = classFile.getConstantPool(); 
        for (String name: cp.getClassNames()) { 
         if (!classes.contains(name)) { 
          classes.add(name); 
         } 
        } 
       } 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

會給你一個類的所有依賴。應用於org.jedo.classfile時。ClassFile,它會產生以下輸出:

file:/D:/projects/casagrande/jedo/build/classes/org/jedo/classfile/ClassFile.class 
file:/D:/projects/casagrande/jedo/build/classes/org/jedo/classfile/ConstantPool.class 
file:/D:/projects/casagrande/jedo/build/classes/org/jedo/classfile/FieldInfo.class 
file:/D:/projects/casagrande/jedo/build/classes/org/jedo/classfile/MethodInfo.class 
file:/D:/projects/casagrande/jedo/build/classes/org/jedo/classfile/AttributeInfo.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/File.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/FileInputStream.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/DataInputStream.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/StreamCorruptedException.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/FileOutputStream.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/DataOutputStream.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/lang/StringBuilder.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/lang/StringBuffer.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/lang/Object.class 
jar:file:/C:/Program%20Files/Java/jdk1.6.0_18/jre/lib/rt.jar!/java/io/IOException.class 
... 

後面跟着很多系統類。您需要過濾掉系統類,並解析其他URL以提取.jar文件(如果它是jar)或url(如果它是文件:url)。

+0

我會解決一些分析字節碼的問題,如果它遞歸地通過類加載器找到的類 – IttayD 2010-08-09 05:59:47

0

有些情況下,在使用類之前無法確定此類。

0

這並不總是可知的。例如,一個類可以在運行時動態創建,然後加載自定義的ClassLoader

我不相信Java存儲此信息。

+0

因爲我想在外部運行它,讓我們假設我知道所有的依賴項都是從實際的文件/ jar中檢索的。 – IttayD 2010-08-09 05:22:22

2

我不認爲這是可能的。當然,反射API不支持它。

你可以找到一個類加載器,但你不能找出:

  • 其類加載器的可能的JAR文件和目錄包含類,
  • 什麼類的靜態依賴關係,或
  • 該類的動態依賴關係是什麼;例如它或它的家屬用Class.forName()加載了哪些內容。

其實,這有點誇大的事情:

  • 可以在理論上弄清楚哪些類從JAR文件出來,如果你能找到的類路徑是什麼。有可能的方法從類加載器中挖掘出來。
  • 理論上你可以弄清楚什麼是類的依賴者,但是你一直在使用(例如)BCEL在類的字節碼文件中進行挖掘以找出它。
  • 如果你準備編寫你自己的類加載器,你理論上可以計算出動態加載的內容。有可能通過對堆棧幀進行毛茸茸的分析將其鏈接回啓動加載的類。

但這一切都非常複雜,我認爲它在某些情況下是不可靠的。

+0

clazz.getResource(「/」+ clazz.getName()。replace(「。」,「/」)+「.class」)將返回從中加載文件的文件。刪除以後的一切!會給罐子。 – IttayD 2010-08-09 05:24:21

+0

@IttayD - 我不相信這適用於所有類加載器。 – 2010-08-09 05:39:58