所有依赖项都记录在类文件的中心位置,即常量池。因此,为了有效地处理所有依赖项,您需要一个允许在不查看类文件的其余部分的情况下处理常量池的库(这排除了 ASM,否则它是一个非常好的字节码处理库)。
所以使用,例如Javassist,你可以做这个工作
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;
}
Run Code Online (Sandbox Code Playgroud)
测试它
try(InputStream is = String.class.getResourceAsStream("String.class")) {
set = getDependencies(is);
}
set.stream().sorted().forEachOrdered(System.out::println);
Run Code Online (Sandbox Code Playgroud)
显示
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;
}
Run Code Online (Sandbox Code Playgroud)
(在 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;
}
Run Code Online (Sandbox Code Playgroud)