我正在寻找一种方法来获取jar文件中所有类的方法存根的列表。我不确定从哪里开始…我可以使用Reflection或Javassist或其他我还没有听说过的工具吗?至少有可能打开jar包,反编译类文件并使用行解析器扫描方法,但是我认为这是最肮脏的方法;-)
有任何想法吗?
亲切的问候
根据aioobe的回答,您还可以使用ASM的树API(而不是其访问者API)来解析JAR文件中包含的类文件的内容。同样,您可以使用JarFile类读取JAR文件中包含的文件。这是如何完成此操作的示例:
该printMethodStubs方法接受a JarFile并继续打印出所有类文件中包含的所有方法的描述。
printMethodStubs
JarFile
public void printMethodStubs(JarFile jarFile) throws Exception { Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); if (entryName.endsWith(".class")) { ClassNode classNode = new ClassNode(); InputStream classFileInputStream = jarFile.getInputStream(entry); try { ClassReader classReader = new ClassReader(classFileInputStream); classReader.accept(classNode, 0); } finally { classFileInputStream.close(); } System.out.println(describeClass(classNode)); } } }
该describeClass方法接受一个ClassNode对象并继续对其进行描述及其相关方法:
describeClass
ClassNode
public String describeClass(ClassNode classNode) { StringBuilder classDescription = new StringBuilder(); Type classType = Type.getObjectType(classNode.name); // The class signature (e.g. - "public class Foo") if ((classNode.access & Opcodes.ACC_PUBLIC) != 0) { classDescription.append("public "); } if ((classNode.access & Opcodes.ACC_PRIVATE) != 0) { classDescription.append("private "); } if ((classNode.access & Opcodes.ACC_PROTECTED) != 0) { classDescription.append("protected "); } if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) { classDescription.append("abstract "); } if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) { classDescription.append("interface "); } else { classDescription.append("class "); } classDescription.append(classType.getClassName()).append("\n"); classDescription.append("{\n"); // The method signatures (e.g. - "public static void main(String[]) throws Exception") @SuppressWarnings("unchecked") List<MethodNode> methodNodes = classNode.methods; for (MethodNode methodNode : methodNodes) { String methodDescription = describeMethod(methodNode); classDescription.append("\t").append(methodDescription).append("\n"); } classDescription.append("}\n"); return classDescription.toString(); }
该describeMethod方法接受a MethodNode并返回一个描述方法签名的字符串:
describeMethod
MethodNode
public String describeMethod(MethodNode methodNode) { StringBuilder methodDescription = new StringBuilder(); Type returnType = Type.getReturnType(methodNode.desc); Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc); @SuppressWarnings("unchecked") List<String> thrownInternalClassNames = methodNode.exceptions; if ((methodNode.access & Opcodes.ACC_PUBLIC) != 0) { methodDescription.append("public "); } if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) { methodDescription.append("private "); } if ((methodNode.access & Opcodes.ACC_PROTECTED) != 0) { methodDescription.append("protected "); } if ((methodNode.access & Opcodes.ACC_STATIC) != 0) { methodDescription.append("static "); } if ((methodNode.access & Opcodes.ACC_ABSTRACT) != 0) { methodDescription.append("abstract "); } if ((methodNode.access & Opcodes.ACC_SYNCHRONIZED) != 0) { methodDescription.append("synchronized "); } methodDescription.append(returnType.getClassName()); methodDescription.append(" "); methodDescription.append(methodNode.name); methodDescription.append("("); for (int i = 0; i < argumentTypes.length; i++) { Type argumentType = argumentTypes[i]; if (i > 0) { methodDescription.append(", "); } methodDescription.append(argumentType.getClassName()); } methodDescription.append(")"); if (!thrownInternalClassNames.isEmpty()) { methodDescription.append(" throws "); int i = 0; for (String thrownInternalClassName : thrownInternalClassNames) { if (i > 0) { methodDescription.append(", "); } methodDescription.append(Type.getObjectType(thrownInternalClassName).getClassName()); i++; } } return methodDescription.toString(); }