raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.21k stars 798 forks source link

How to call method self when use Advice #1660

Open twogoods opened 2 months ago

twogoods commented 2 months ago
    @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
    public static boolean enter(@Advice.Origin Method method, 
                                         @Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj) {
               method.invoke();
}

if method is private,you can't use obj.xxx() reflection can do this,decompile source code it looks like A.class.getMethod(xxx).invoke() can has some optimization let code looks like this.xxx()

raphw commented 2 months ago

You can create a static fake method with the same signature and then use MethodSubstitution to replace the method with the actual one.

twogoods commented 2 months ago

You can create a static fake method with the same signature and then use MethodSubstitution to replace the method with the actual one.

sample like this? like retry to invoke method,so I want to call method self in Advice api,I prefer Advice api ,dont add new class、method、field In my case method.invoke can translate to this.xxx() in bytecode?or add some @advice.xxx to describe method call to help bytebuddy translate method call to this.xxx()

twogoods commented 2 months ago

And I have another question can Advice api provider @Advice.AllFields struct like map<name,value>

    @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
    public static boolean enter(@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object[] allArguments){
        method m=findChangeFunctionById();
        allArguments =m.invoke();
}

the code can be a tmp code to change the arguments value,but if I want to change the field I must to write every @Advice.FieldValue(value = "name", readOnly = false)

raphw commented 2 months ago

You can emulate a self-invocation. As you already discovered you can skip a method using skipOn in enter. You can also repeat a method from an exit advice using repeatOn. The value returned from the (previous call to the) exit advice is then available using @Advice.Exit.

This way, you can first just jump over the method from enter. From exit, you can then simply return from exit to invoke the original code and keep track of your state using @Advice.Exit.