如何查找方法中调用的所有方法(包括 Lamda)?

Tri*_*ind 0 java bytecode cglib javassist byte-buddy

我想列出一个方法调用的所有方法。

void create() throws MyException {
    System.out.println("TEST");
    of("String").map(String::valueOf).get();
}
Run Code Online (Sandbox Code Playgroud)

在这个方法中我想列出

  • 系统输出打印文件
  • 地图
  • 字符串::值
  • 得到();

我习惯了下面的代码,如何找到一个方法中调用的所有方法?

public class MethodFinder {

  public static void main(String[] args) throws Throwable {
    ClassPool cp = ClassPool.getDefault();
    CtClass ctClass = cp.get("MyClass");
    CtMethod method = ctClass.getDeclaredMethod("getItem1");
    method.instrument(
        new ExprEditor() {
            public void edit(MethodCall m)
                          throws CannotCompileException
            {
                System.out.println(m.getClassName() + "." + m.getMethodName() + " " + m.getSignature());
            }
        });
  }
}
Run Code Online (Sandbox Code Playgroud)

并获取除 String::valueOf 之外的所有方法

是否可以通过任何其他框架解决这个问题并不重要。

Hol*_*ger 5

由于String.valueOf实际上不是由方法调用的,因此 I\xe2\x80\x99d 使用更广泛的术语,例如谈论包含调用方法的引用方法使用ASM ( )收集所有这些信息的一种方法是:

\n\n
import java.io.IOException;\nimport java.util.Optional;\nimport org.objectweb.asm.*;\n\npublic class FindAllReferencedMethods {\n    class Example {\n        void create() {\n            System.out.println("TEST");\n            Optional.of("String").map(String::valueOf).get();\n        }\n    }\n    public static void main(String[] args) throws IOException {\n        ClassReader r = new ClassReader(Example.class.getName());\n        r.accept(new ClassVisitor(Opcodes.ASM5) {\n            @Override\n            public MethodVisitor visitMethod(\n                   int access, String name, String desc, String sig, String[] ex) {\n                return name.equals("create")? new MethodRefCollector(): null;\n            }\n\n        }, ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);\n    }\n\n    static void referencedMethod(String owner, String name, String desc) {\n        System.out.println(\n            Type.getObjectType(owner).getClassName() + "." + name + " " + desc);\n    }\n\n    static class MethodRefCollector extends MethodVisitor {\n        public MethodRefCollector() {\n            super(Opcodes.ASM5);\n        }\n\n        @Override\n        public void visitMethodInsn(\n                    int opcode, String owner, String name, String desc, boolean itf) {\n            referencedMethod(owner, name, desc);\n        }\n\n        @Override\n        public void visitInvokeDynamicInsn(\n                    String name, String desc, Handle bsm, Object... bsmArgs) {\n            if(bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")\n            && bsm.getDesc().equals(bsm.getName().equals("altMetafactory")?\n                                    ALT_SIG: MF_SIG)) {\n                Handle target = (Handle)bsmArgs[1];\n                referencedMethod(target.getOwner(), target.getName(), target.getDesc());\n            }\n        }\n    }\n    static String MF_SIG = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;"\n        +"Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/"\n        +"MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";\n    static String ALT_SIG = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;"\n        +"Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;";\n}\n
Run Code Online (Sandbox Code Playgroud)\n