question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to advise a method after this method has been intercepted.

See original GitHub issue

Hi, I found it does not work to advise a method after this method has been intercepted. Here is demo code :

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.agent.builder.AgentBuilder.Listener;
import net.bytebuddy.agent.builder.ResettableClassFileTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.utility.JavaModule;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.Instrumentation;

import static net.bytebuddy.matcher.ElementMatchers.named;

public class Main {

    private static final InstrumentationProvider provider = InstrumentationProviderImpl.INSTANCE;

    public static void main(String[] args) {
        Instrumentation instrumentation = provider.findInstrumentation();

        AgentBuilder.Identified.Extendable iExtendable = null;
        ResettableClassFileTransformer iResettable = null;
        AgentBuilder.Default iBuilder = new AgentBuilder.Default();
        iExtendable = iBuilder.type(named("Person"))
                .transform((builder, typeDescription, classLoader, module) -> {
                    builder = builder.method(named("say")).intercept(MethodDelegation.to(CallInterceptor.class));
                    return builder;
                });
        iResettable = iExtendable.with(new Listener.WithTransformationsOnly(Listener.StreamWriting.toSystemOut()) {
            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
                super.onTransformation(typeDescription, classLoader, module, loaded, dynamicType);
                outputClassContentToFile(typeDescription, dynamicType, "interceptor");
            }
        })
                .installOn(instrumentation);


        System.out.println("before agent");
        Person person = new Person();
        person.say();

        showLoadedClass(instrumentation);

        AgentBuilder.Identified.Extendable extendable = null;
        ResettableClassFileTransformer resettable = null;
        AgentBuilder.Default builder = new AgentBuilder.Default();
        extendable = builder.type(named("Person"))
                .transform((innerBuilder, typeDescription, classLoader, module) -> {
                    innerBuilder = innerBuilder.visit(
                            Advice.to(CallAdvisor.class)
                                    .on(named("say")));
                    return innerBuilder;
                });
        resettable = extendable.with(new Listener.WithTransformationsOnly(Listener.StreamWriting.toSystemOut()) {
            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
                super.onTransformation(typeDescription, classLoader, module, loaded, dynamicType);
                outputClassContentToFile(typeDescription, dynamicType, "advisor");
            }
        })
                .disableClassFormatChanges()
                .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
                .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .installOn(instrumentation);


        System.out.println("after agent used");
        person.say();

        showLoadedClass(instrumentation);

        if (resettable != null) {
            resettable.reset(instrumentation,
                    AgentBuilder.RedefinitionStrategy.REDEFINITION,
                    AgentBuilder.RedefinitionStrategy.DiscoveryStrategy.Reiterating.INSTANCE,
                    AgentBuilder.RedefinitionStrategy.BatchAllocator.ForFixedSize.ofSize(1),
                    AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemOut()
            );
        }

        System.out.println("after agent reset");
        person.say();
    }
}

import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.implementation.bind.annotation.This;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class CallInterceptor {

    @RuntimeType
    public static Object intercept(
            @This(optional = true) Object origin,
            @Origin(cache = false) Method method,
            @SuperCall Callable<?> callable,
            @AllArguments Object[] args
    ) throws Exception {
        // need all of the parameters
        System.out.println("intercept call");
        return callable.call();
    }
}
import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner;

import java.lang.reflect.Method;

public class CallAdvisor {

    @Advice.OnMethodEnter
    public static void onMethodEnter(@Advice.This(typing = Assigner.Typing.DYNAMIC) Object origin,
                                     @Advice.Origin Method method,
                                     @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments) {
        System.out.println("call enter");
    }

    @Advice.OnMethodExit(onThrowable = Throwable.class)
    public static void onMethodExit(@Advice.This(typing = Assigner.Typing.DYNAMIC) Object origin,
                                    @Advice.Origin Method method,
                                    @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments,
                                    @Advice.Return(readOnly = true, typing = Assigner.Typing.DYNAMIC) Object ret,
                                    @Advice.Thrown(readOnly = true, typing = Assigner.Typing.DYNAMIC) Throwable e) {
        if (e != null) {
            System.out.println(e.getMessage());
        }
        System.out.println("call left");
    }
}

public class Person {
    public void say() {
        System.out.println("hello");
    }
}

And here is the output:

before agent [Byte Buddy] TRANSFORM Person [sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=false] intercept call hello Person$auxiliary$GnBTihZL loaded after agent Person loaded after agent [Byte Buddy] TRANSFORM Person [sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=true] [Byte Buddy] TRANSFORM Person [sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=true] after agent used intercept call hello Person$auxiliary$GnBTihZL loaded after agent Person loaded after agent [Byte Buddy] REDEFINE BATCH #0 [1 of 1 type(s)] [Byte Buddy] TRANSFORM Person [sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=true] [Byte Buddy] REDEFINE ERROR #0 [1 of 1 type(s)] java.lang.UnsupportedOperationException: class redefinition failed: attempted to delete a method at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method) at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170) at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector$ForRedefinition.doApply(AgentBuilder.java:7165) at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector.apply(AgentBuilder.java:7032) at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy.apply(AgentBuilder.java:4868) at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.reset(AgentBuilder.java:10395) at net.bytebuddy.agent.builder.ResettableClassFileTransformer$AbstractBase.reset(ResettableClassFileTransformer.java:358) at Main.main(Main.java:87) [Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 1 types [1 failed batch(es)] [Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 0 types [0 failed batch(es)] after agent reset intercept call hello

The output show that the CallAdvisor does not work.

Is there any way to advise a method after this method has been intercepted.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
raphwcommented, Jul 20, 2020

I see, REDEFINITION is only recommended in few cases or when using Java 5. Good it worked out!

0reactions
yaohwucommented, Jul 20, 2020

yes,it worked,thank you for your help

Read more comments on GitHub >

github_iconTop Results From Across the Web

AspectJ: Intercept return result of method inside another method
1 Answer 1 ... You need to limit your pointcut to the executions within the control flow - cflow() - of the calling...
Read more >
Intercepting Methods - PostSharp 6.10 Documentation
The current article covers method interception, for another approach to injecting behaviors into methods, see Injecting Behaviors Before and After Method ...
Read more >
Chapter 6. Spring AOP: Aspect Oriented Programming with ...
The most fundamental advice type in Spring is interception around advice. Spring is compliant with the AOP Alliance interface for around advice using...
Read more >
Spring AOP Example Tutorial - Aspect, Advice, Pointcut ...
After Returning Advice: Sometimes we want advice methods to execute only if the join point method executes normally. We can use @AfterReturning ...
Read more >
Intercept Grails Service Class Method Calls | TO THE NEW Blog
Now we need to declare an advice. Advice is associated with a pointcut expression, and runs before, after, or around method executions matched ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found