Java: Easy way to get method stub out of class files within a JAR file? Reflection?

后端 未结 2 1345
天涯浪人
天涯浪人 2021-02-04 17:41

I\'m searching for a way to get a list of method stubs of all classes within a jar file. I\'m not sure where to start... May I use Reflection or Javassist or some other tools of

相关标签:
2条回答
  • 2021-02-04 18:25

    The best way I can think of is to use the ASM-bytecode framework. Then at least you wouldn't have to go through some decompilation-output with a line-parser. In fact, getting the method-stubs should be like a 20-line implementation of one of their Visitor-interfaces.

    I've used it myself for bytecode rewriting and it's fairly simple and straight forward (especially if you're just reading the class-files).

    http://asm.ow2.org/

    0 讨论(0)
  • 2021-02-04 18:26

    Building upon aioobe's answer, you can also use ASM's tree API (as opposed to its visitor API) to parse the contents of the class files contained within your JAR file. As well, you can read the files contained within the JAR file using the JarFile class. Here is an example of how this could be done:

    The printMethodStubs method accepts a JarFile and proceeds to print out descriptions of all methods contained within all class files.

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

    The describeClass method accepts a ClassNode object and proceeds to describe it and its associated methods:

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

    The describeMethod method accepts a MethodNode and returns a String describing the method's signature:

    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();
    }
    
    0 讨论(0)
提交回复
热议问题