以(编程方式)解析已编译的Java(.class)文件并生成其引用的任何和所有其他Java类的列表的最佳方式是什么?确定.class文件中引用的类
4
A
回答
7
如果您知道the spec,很容易就可以做到。
继承人快速和肮脏的演示程序是如何做到这一点:
package test;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public class Main {
private static Map<Integer, String> strings = new HashMap<Integer, String>();
private static Set<Integer> classes = new HashSet<Integer>();
private static int indexCorrection = 0; // for correcting indexes to constant pools with long and double entries
public static void main(String[] args) throws Exception {
printReferencedClassesFromClass(String.class);
}
private static void printReferencedClassesFromClass(Class<?> c) throws IOException {
saveReferencedClassesFromStream(c.getResourceAsStream(c.getSimpleName() + ".class"));
printReferencedClasses();
}
private static void printReferencedClasses() {
for (Integer index : classes)
System.out.println(strings.get(index));
}
private static void saveReferencedClassesFromStream(InputStream stream) throws IOException {
DataInputStream dataStream = new DataInputStream(stream);
skipHeader(dataStream);
saveReferencedClassesFromConstantPool(dataStream);
}
private static void skipHeader(DataInputStream dataInputStream) throws IOException {
readU4(dataInputStream); // magic byte
readU2(dataInputStream); // minor version
readU2(dataInputStream); // major version
}
private static void saveReferencedClassesFromConstantPool(DataInputStream stream) throws IOException {
int poolSize = readU2(stream);
for (int n = 1; n < poolSize - indexCorrection; n++)
savePoolEntryIfIsClassReference(n, stream);
}
private static void savePoolEntryIfIsClassReference(int index, DataInputStream stream) throws IOException {
int tag = readU1(stream);
switch (tag) {
case 1: // Utf8
saveStringFromUtf8Entry(index, stream);
break;
case 7: // Class
saveClassEntry(stream);
break;
case 8: // String
case 16: // MethodType
readU2(stream);
break;
case 3: // Integer
case 4: // Float
readU4(stream);
break;
case 5: // Long
case 6: // Double
readU4(stream);
readU4(stream);
indexCorrection++;
break;
case 9: // Fieldref
case 10: // Methodref
case 11: // InterfaceMethodref
case 12: // NameAndType
case 18: // InvokeDynmaic
readU2(stream);
readU2(stream);
break;
case 15: // MethodHandle
readU1(stream);
readU2(stream);
break;
}
}
private static void saveClassEntry(DataInputStream stream) throws IOException {
classes.add(readU2(stream));
}
private static void saveStringFromUtf8Entry(int index, DataInputStream stream) throws IOException {
strings.put(index + indexCorrection, readString(stream));
}
private static String readString(DataInputStream stream) throws IOException {
return stream.readUTF();
}
private static int readU1(DataInputStream stream) throws IOException {
return stream.readUnsignedByte();
}
private static int readU2(DataInputStream stream) throws IOException {
return stream.readUnsignedShort();
}
private static int readU4(DataInputStream stream) throws IOException {
return stream.readInt();
}
}
输出是:
test/Main
java/lang/Object
java/io/BufferedInputStream
java/util/Iterator
java/io/FileInputStream
java/lang/System
java/lang/Integer
java/lang/Exception
java/lang/String
java/io/File
java/util/Map
java/util/HashMap
java/io/IOException
java/util/Set
java/io/DataInputStream
java/io/PrintStream
java/util/HashSet
java/lang/Throwable
1
您是否试过JDepend?它分析类文件以确定引用。
0
我不知道最好的方法是什么。我知道有2个API可能有帮助。
您可以尝试jclasslib,用于检查的.class用于分析和操纵的.class文件的文件
http://www.ej-technologies.com/products/jclasslib/resources.html
或BCEL(字节码工程库)。
http://jakarta.apache.org/bcel/
我的理解是任何在类中使用的类(只要字段,参数,返回类型等)都是在constant_pool中定义的。所以你可能想要阅读。
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
1
这可能与Apache的BCEL有关。
0
我想你可以使用我的Java Dependency Resolver project哪个会发现不仅被引用的Java文件但也在一个项目中的特定类的罐子
相关问题
- 1. 对一个文件中Class :: Class()和函数的未定义引用? C++
- 2. 对'Class :: Class'的未定义引用
- 3. 未定义的引用`Class :: Class()'
- 4. 未定义的引用Class :: Class()和Class :: function()
- 5. 从需要的.class文件中间接引用导入jar和类型
- 6. 无法解析类型org.apache.http.Header。它是间接需要的.class文件中引用
- 7. 无法解析com.google.firebase.iid.zzb类型。它是间接需要的.class文件中引用
- 8. 类无法解析。它是直接从所需要的.class文件中引用
- 9. Javac无法找到.class文件,没有正确的类路径
- 10. 确定资产文件夹中文件的文件类型
- 11. Dim类正在被.class文件使用
- 12. 确实需要的Java .class文件,即使定义
- 13. 对“Class :: method”C++的未定义引用?
- 14. 未定义的引用CLASS ::函数()
- 15. 无法确定类型为“Class”的JSON对象类型
- 16. Eclipse引用.class文件而不是工作区java文件
- 17. 使用C#确定文件类型
- 18. 正确的动态类生成使用Moose :: Meta :: Class或Class :: MOP :: Class
- 19. 自定义异常类未被编译到.class文件中
- 20. 未定义对`class :: class()的引用错误
- 21. C#中确定引用的dll文件版本#
- 22. 无法解析junit.framework.TestCase类型。它是从所需的.class文件间接引用
- 23. 引用.kv文件中的类属性
- 24. 无法确定文件的MIME类型
- 25. 确定图像的文件类型
- 26. 确定excel文件的MIME类型
- 27. 确定文件的MIME类型
- 28. Sox无法确定文件的类型
- 29. 确定程序集引用某些类
- 30. 对'typeinfo for class'的未定义引用以及对'class'的vtable的未定义引用
不幸的是不是每次都工作,必须是某处的错误。在guava-17上的'ImmutableSetMultimap.class'上试试。它会将“无效的密钥计数”字符串视为类名称。另外,尝试在'switch(tag)'中添加'default'部分:它会在常量池的末尾用'tag == 0'触发 – eprst 2016-08-24 21:37:51
我修复了这个bug并修改了代码以使用java 8。如果这些格式将其他标签类型添加到常量池中,则可以再次使用较新的类文件格式进行打破。 – Arne 2016-08-26 15:14:13