从类中获取完整的类路径

发布于 2024-09-14 04:00:50 字数 185 浏览 7 评论 0原文

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

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

I'm looking a utility method so that given a class will return the full classpath required to run this class externally. This means the jar the class is in as well as all jars (or folders) of classes that it uses.

UPDATE: there are tools that analyze .class files to find dependencies. This is not what I'm looking for. I'm looking for something that uses Java's reflection API on an already loaded class. I'll settle for something that analyzes byte code, if it goes recursively into classes it finds through the class loader

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

つ可否回来 2024-09-21 04:00:50

对于这一点,反思不会对你有太大帮助。您将需要分析字节码以查找依赖项。

更新:

那么好吧。我正在使用几年前制作的一个库,您可以在此处下载。

以下代码:

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)或目录(如果它是 file: url)。

Reflection will not help you a lot for this one. You will need to analyse the byte code to find dependencies.

UPDATE:

Alright then. I am using a library that I made years ago, that you can download here.

The following code:

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();
        }
    }
}

Will give you all the dependencies of a class. When applied to org.jedo.classfile.ClassFile, it produces the following output:

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
...

Followed by a lot of system classes. You need to filter out system classes, and parse the other urls to extract either the .jar file if it is a jar: url, or the directory if it is a file: url.

路弥 2024-09-21 04:00:50

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

你可以找到一个classes类加载器,但你无法找到:

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

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

  • 理论上,如果您能找出类路径是什么,您就可以找出哪些类来自哪些 JAR。可能有一些方法可以从类加载器中挖掘出它。
  • 理论上,您可以弄清楚类依赖项是什么,但您需要使用(例如)BCEL 在类的字节码文件中进行挖掘才能找到答案。
  • 如果您准备编写自己的类加载器,理论上您可以弄清楚动态加载的内容。可以使用对堆栈帧的一些复杂分析将其链接回启动加载的类。

但这一切都非常复杂,我预计它在某些情况下是不可靠的。

I don't think this is possible. Certainly, the reflection APIs don't support it.

You can find out a classes classloader, but you cannot find out:

  • which of the classloader's possible JAR files and directories contained the class,
  • what the static dependencies of the class are, or
  • what the dynamic dependencies of the class are; e.g. what it or its dependants loaded using Class.forName().

Actually, this overstates things somewhat:

  • You can in theory figure out which classes came from which JARs if you can find out what the classpath is. There are possibly ways to dig this out of a classloader.
  • You can in theory figure out what a classes dependants are, but you been to dig around in the class'es bytecode file using (for instance) BCEL to find this out.
  • You can in theory figure out what was dynamically loaded if you are prepared to write your own classloader. It may be possible to link this back to the class that initiated the loading using some hairy analysis of the stack frames.

But this is all extremely complicated, and I'd expect it to be unreliable under certain circumstances.

满意归宿 2024-09-21 04:00:50

在某些情况下,您无法在使用课程之前确定这一点。

There are cases when you cannot determine this prior to using your class.

愁以何悠 2024-09-21 04:00:50

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

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

This cannot always be known. For instance, a class can be dynamically created at run time and then loaded with a custom ClassLoader.

I do not believe Java stores this information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文