2010-08-09 247 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