通过Java从.class文件中获取ByteCode(依赖项)信息 [英] Get ByteCode (dependency) information from .class files through Java
问题描述
我想分析.class
文件并获取有关哪个类使用哪个其他类的信息.
I would like to analyse .class
files and get information about which class uses which other class.
jdeps
是一个命令行工具,可让您在控制台中显示一些信息,但我想避免调用外部工具并抓取命令行输出.
jdeps
is a command line tool which allows you to display some information in the console, but I would like to avoid calling an external tool and scraping the command line output.
推荐答案
所有依赖项都记录在类文件(常量池)的中央位置.因此,要有效地处理所有依赖关系,您需要一个无需处理类文件即可处理常量池的库(排除了ASM,否则它是一个非常好的字节码处理库).
All dependencies are recorded at a central place of a class file, the constant pool. So to efficiently process all dependencies, you need a library allowing to process the constant pool without looking at the rest of the class file (which rules out ASM, which is otherwise a very good bytecode processing library).
例如,使用 Javassist ,您可以按照以下方式完成工作
So using, e.g. Javassist, you can do the job as
private static Set<String> getDependencies(InputStream is) throws IOException {
ClassFile cf = new ClassFile(new DataInputStream(is));
ConstPool constPool = cf.getConstPool();
HashSet<String> set = new HashSet<>();
for(int ix = 1, size = constPool.getSize(); ix < size; ix++) {
int descriptorIndex;
switch (constPool.getTag(ix)) {
case ConstPool.CONST_Class: set.add(constPool.getClassInfo(ix));
default: continue;
case ConstPool.CONST_NameAndType:
descriptorIndex = constPool.getNameAndTypeDescriptor(ix);
break;
case ConstPool.CONST_MethodType:
descriptorIndex = constPool.getMethodTypeInfo(ix);
}
String desc = constPool.getUtf8Info(descriptorIndex);
for(int p = 0; p<desc.length(); p++)
if(desc.charAt(p)=='L')
set.add(desc.substring(++p, p = desc.indexOf(';', p)).replace('/', '.'));
}
return set;
}
使用
try(InputStream is = String.class.getResourceAsStream("String.class")) {
set = getDependencies(is);
}
set.stream().sorted().forEachOrdered(System.out::println);
显示
[B
[C
[I
[Ljava.lang.CharSequence;
[Ljava.lang.String;
java.io.ObjectStreamField
java.io.Serializable
java.io.UnsupportedEncodingException
java.lang.AbstractStringBuilder
java.lang.CharSequence
java.lang.Character
java.lang.Comparable
java.lang.Double
java.lang.Float
java.lang.IndexOutOfBoundsException
java.lang.Integer
java.lang.Iterable
java.lang.Long
java.lang.Math
java.lang.NullPointerException
java.lang.Object
java.lang.OutOfMemoryError
java.lang.String
java.lang.String$1
java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
java.lang.StringCoding
java.lang.StringCoding$Result
java.lang.StringIndexOutOfBoundsException
java.lang.StringLatin1
java.lang.StringLatin1$CharsSpliterator
java.lang.StringUTF16
java.lang.StringUTF16$CharsSpliterator
java.lang.StringUTF16$CodePointsSpliterator
java.lang.System
java.lang.Throwable
java.lang.Void
java.nio.charset.Charset
java.util.ArrayList
java.util.Arrays
java.util.Comparator
java.util.Formatter
java.util.Iterator
java.util.List
java.util.Locale
java.util.Objects
java.util.Spliterator
java.util.Spliterator$OfInt
java.util.StringJoiner
java.util.regex.Matcher
java.util.regex.Pattern
java.util.stream.IntStream
java.util.stream.StreamSupport
(在Java 9上)
您可以使用 BCEL
private static Set<String> getDependencies(InputStream is) throws IOException {
JavaClass cf = new ClassParser(is, "").parse();
ConstantPool constPool = cf.getConstantPool();
HashSet<String> set = new HashSet<>();
constPool.accept(new DescendingVisitor(cf, new EmptyVisitor() {
@Override public void visitConstantClass(ConstantClass cC) {
set.add(((String)cC.getConstantValue(constPool)).replace('/', '.'));
}
@Override public void visitConstantNameAndType(ConstantNameAndType cNaT) {
processSignature(cNaT.getSignature(constPool));
}
@Override public void visitConstantMethodType(ConstantMethodType cMt) {
processSignature(
constPool.constantToString(cMt.getDescriptorIndex(),
(byte)ConstPool.CONST_Utf8));
}
private void processSignature(String desc) {
for(int p = 0; p<desc.length(); p++)
if(desc.charAt(p)=='L')
set.add(desc.substring(++p, p=desc.indexOf(';', p)).replace('/', '.'));
}
}));
return set;
}
这篇关于通过Java从.class文件中获取ByteCode(依赖项)信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!