Search code examples
javainstrumentationbyte-buddy

How to advice constructor of original class after define a field using bytebuddy


I am trying to define a field to a class and use it with advice. I try this with normal methods but i can't use this with constructor.I try using

.constructor(ElementMatchers.any())
 .intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(MethodListener.class)))

but then advice not running. I have code as follows..

Agent

new AgentBuilder.Default()
                .with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
                .type(ElementMatchers.nameContains("BalConnectorCallback"))
                .transform((builder, typeDescription, classLoader, module) -> builder
                        .defineField("contextTimer", Timer.Context.class)
                        .method(ElementMatchers.any())
                        .intercept(Advice.to(MethodListener.class))
                ).installOn(instrumentation);

This is my advice

public class MethodListener {
    @Advice.OnMethodEnter
    public static void enter(@Advice.Origin String method,
                             @Advice.AllArguments Object[] para,
                             @Advice.FieldValue(value = "contextTimer", readOnly = false) Timer.Context contextTimer)
            throws Exception {

        if (getMethodName(method).equals("BalConnectorCallback")) {
            contextTimer = metricServer.getResponsesTime().start();
        }

    }

    @Advice.OnMethodExit
    public static void exit(@Advice.Origin String method,
                            @Advice.FieldValue("contextTimer") Timer.Context contextTimer)
            throws Exception {


        if (getMethodName(method).equals("done")) {
           contextTimer.stop();
        }
    }
}

How to advice constructor with define a field?


Solution

  • Hi got this problem corrected by using

    .constructor(ElementMatchers.any())
     .intercept(Advice.to(ConstructorAdvice.class))
    

    and Created a another Advice for constructor as follows

    public class ConstructorAdvice {
        @Advice.OnMethodExit
        public static void enter(@Advice.Origin String method,
                                 @Advice.AllArguments Object[] para,
                                 @Advice.FieldValue(value = "contextTimer", readOnly = false) Timer.Context contextTimer)
                throws Exception {
    
            if (getMethodName(method).equals("BalConnectorCallback")) {
                contextTimer = metricServer.getResponsesTime().start();
            }
    
        }