从类中获取完整的类路径

时间:2010-08-09 04:55:37

标签: java classpath dependencies

我正在寻找一个实用程序方法,以便给定一个类将返回从外部运行此类所需的完整类路径。这意味着类所在的jar以及它使用的所有类的jar(或文件夹)。

更新:有一些工具可以分析.class文件以查找依赖项。这不是我想要的。我正在寻找在已经加载的类上使用Java反射API的东西。我会满足于分析字节代码的东西,如果它递归地进入它通过类加载器找到的类

4 个答案:

答案 0 :(得分:2)

我不认为这是可能的。当然,反射API不支持它。

你可以找到一个类类加载器,但你找不到:

  • 哪个类加载器的可能JAR文件和目录包含该类
  • 类的静态依赖项是什么,或
  • 类的动态依赖关系是什么;例如使用Class.forName()加载它或其家属的内容。

实际上,这有点夸大了事情:

  • 如果你能找到类路径是什么,理论上可以找出哪些类来自哪些JAR。有可能从类加载器中挖掘出来。
  • 理论上你可以弄清楚一个类的依赖是什么,但你一直在使用(例如)BCEL在类的字节码文件中找到它。
  • 如果您准备编写自己的类加载器,理论上可以找出动态加载的内容。可以使用堆栈帧的一些毛茸茸的分析将其链接回启动加载的类。

但这一切都非常复杂,我希望在某些情况下它不可靠。

答案 1 :(得分: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。

答案 2 :(得分:0)

有些情况下,在使用课程之前无法确定。

答案 3 :(得分:0)

这并不总是可以知道的。例如,可以在运行时动态创建类,然后使用自定义ClassLoader加载。

我不相信Java会存储这些信息。