0

Here's my use case: I have a class that has multiple methods that I want to intercept, but I don't want to intercept all methods of this class. I want to use different instances of the same interceptor class to accomplish this. When I try to do this, I'm seeing behavior that I don't understand from Byte Buddy. I'm pretty sure it's something I don't understand and/or something I'm doing wrong, but I'm stumped. I'm using Byte Buddy 1.6.9.

Class whose methods I want to intercept:

public class MyClass
{
    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    public void firstInterceptedMethod()
    {
        logger.info("firstInterceptedMethod");
    }

    public void secondInterceptedMethod()
    {
        logger.info("secondInterceptedMethod");     
    }

    public void notInterceptedMethod()
    {
        logger.info("notInterceptedMethod");        
    }
}

Interceptor class:

public class MyInterceptor
{
    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    private final UUID identifier = UUID.randomUUID();

    @RuntimeType
    public Object methodCalled(@SuperCall Callable<?> superCall, @Origin Method method) throws Exception
    {
        logger.info("methodCalled: identifier: " + identifier);
        logger.info("methodCalled: method name: " + method.getName());

        return superCall.call();
    }

}

Byte Buddy test/instrumentation:

public class MyTest
{
    @Test
    public void test() throws Exception
    {
        MyInterceptor firstMethodInterceptor = new MyInterceptor();
        MyInterceptor secondMethodInterceptor = new MyInterceptor();

        MyClass myClass = new ByteBuddy().subclass(MyClass.class)
                .method(ElementMatchers.named("firstInterceptedMethod"))
                        .intercept(MethodDelegation.to(firstMethodInterceptor))
                .method(ElementMatchers.named("secondInterceptedMethod"))
                        .intercept(MethodDelegation.to(secondMethodInterceptor))
                .make()
                .load(MyClass.class.getClassLoader())
                .getLoaded()
                .newInstance(); 

        myClass.firstInterceptedMethod();
        myClass.secondInterceptedMethod();
    }
}

Output:

04/20/2017 08:27:26:600 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: identifier: 04124951-f865-4815-8bd4-0b10c0c816a2
04/20/2017 08:27:26:600 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: identifier: 04124951-f865-4815-8bd4-0b10c0c816a2
04/20/2017 08:27:26:613 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: method name: firstInterceptedMethod
04/20/2017 08:27:26:613 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: method name: firstInterceptedMethod
04/20/2017 08:27:26:614 AM [main] bytebuddy.test.MyClass firstInterceptedMethod : INFO firstInterceptedMethod
04/20/2017 08:27:26:614 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: identifier: 79590462-b87d-4125-9e87-5481e1062b05
04/20/2017 08:27:26:614 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: identifier: 79590462-b87d-4125-9e87-5481e1062b05
04/20/2017 08:27:26:614 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: method name: secondInterceptedMethod
04/20/2017 08:27:26:614 AM [main] bytebuddy.test.MyInterceptor methodCalled : INFO methodCalled: method name: secondInterceptedMethod
04/20/2017 08:27:26:614 AM [main] bytebuddy.test.MyClass secondInterceptedMethod : INFO secondInterceptedMethod

My question is: Why am I seeing each interceptor getting called twice? When calling the first method, the first interceptor instance appears to get called twice, and I don't understand why this is. Similar behavior with the second method, only the second interceptor instance appears to get called twice. I would expect the interceptor to only get called once per intercepted method invocation.

If I do something like:

    FirstMethodInterceptor firstMethodInterceptor = new FirstMethodInterceptor();
    SecondMethodInterceptor secondMethodInterceptor = new SecondMethodInterceptor();

then I see behavior that I would expect; i.e., each interceptor is only called once per intercepted method. I'm hoping to avoid this as I would like to be able to reuse a 'common' interceptor without seeing this behavior. Insight would be much appreciated, thanks.

rekgm_chan
  • 41
  • 4

1 Answers1

1

Yeah, as usual it's something I'm doing wrong. This is an artifact of the logger, not of Byte Buddy. Multiple logging handlers are being registered for the same logger instance and that's what's causing this.

rekgm_chan
  • 41
  • 4