【问题标题】:how to find all methods called in a methods including Lamda?如何找到包括Lamda在内的方法中调用的所有方法?
【发布时间】:2017-11-03 17:45:18
【问题描述】:

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

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

我想在这个方法中列出

  • System.out.println
  • 地图
  • String::valueOf
  • get();

我已经习惯了以下代码,来自how to find all methods called in a method?

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

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

这是否由任何其他框架解决都没关系。

【问题讨论】:

  • 请注意这是正确的,因为您的方法create 没有调用方法String.valueOf,而只是获取对该方法的引用并将其传递给map 方法。严格来说,您的方法不知道传递的方法是否真的被调用过。
  • 有什么办法可以解决:)?
  • 我只需要传入的方法的引用
  • 你的代码没有列出System.out.println,因为那不是方法调用。方法调用是println,应用于PrintStream 实例。除此之外,你不应该import staticof 这样的方法。仅在 JRE API 中就有 60 多个同名的方法,您迫使读者猜测实际方法,尤其是在这个问题中,我们无法向上滚动到您的 import 语句。

标签: java bytecode javassist cglib byte-buddy


【解决方案1】:

由于该方法实际上并未调用String.valueOf,因此我将使用更广泛的术语,例如讨论引用的方法,其中包括调用的方法。使用ASM() 收集所有这些的一种方法是:

import java.io.IOException;
import java.util.Optional;
import org.objectweb.asm.*;

public class FindAllReferencedMethods {
    class Example {
        void create() {
            System.out.println("TEST");
            Optional.of("String").map(String::valueOf).get();
        }
    }
    public static void main(String[] args) throws IOException {
        ClassReader r = new ClassReader(Example.class.getName());
        r.accept(new ClassVisitor(Opcodes.ASM5) {
            @Override
            public MethodVisitor visitMethod(
                   int access, String name, String desc, String sig, String[] ex) {
                return name.equals("create")? new MethodRefCollector(): null;
            }

        }, ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
    }

    static void referencedMethod(String owner, String name, String desc) {
        System.out.println(
            Type.getObjectType(owner).getClassName() + "." + name + " " + desc);
    }

    static class MethodRefCollector extends MethodVisitor {
        public MethodRefCollector() {
            super(Opcodes.ASM5);
        }

        @Override
        public void visitMethodInsn(
                    int opcode, String owner, String name, String desc, boolean itf) {
            referencedMethod(owner, name, desc);
        }

        @Override
        public void visitInvokeDynamicInsn(
                    String name, String desc, Handle bsm, Object... bsmArgs) {
            if(bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")
            && bsm.getDesc().equals(bsm.getName().equals("altMetafactory")?
                                    ALT_SIG: MF_SIG)) {
                Handle target = (Handle)bsmArgs[1];
                referencedMethod(target.getOwner(), target.getName(), target.getDesc());
            }
        }
    }
    static String MF_SIG = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;"
        +"Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/"
        +"MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
    static String ALT_SIG = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;"
        +"Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;";
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-30
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    相关资源
    最近更新 更多