byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

[Question] How do I call an intercepted method in an interceptor?

Open luckyQing opened this issue 1 year ago • 2 comments

I want to call the intercepted method in the interceptor. It made a mistake.

The error info: java.lang.IllegalArgumentException: None of [public static java.lang.Object com.demo.bytebuddy.advice.RegisterInterceptor.intercept(java.lang.Object,com.demo.bytebuddy.dto.RegisterReqDTO,com.demo.bytebuddy.service.impl.UserServiceImpl,java.util.concurrent.Callable) throws java.lang.Exception] allows for delegation from public com.demo.bytebuddy.dto.RegisterRespDTO com.demo.bytebuddy.service.impl.UserServiceImpl.register(com.demo.bytebuddy.dto.RegisterReqDTO)

The code is as follows

@Test
public void testInterceptor() {
        ByteBuddyAgent.install();
        new ByteBuddy()
                .redefine(UserServiceImpl.class)
                .method(named("register"))
                .intercept(MethodDelegation.to(RegisterInterceptor.class))
                .make()
                .load(Foo.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

        RegisterReqDTO reqDTO = new RegisterReqDTO();
        reqDTO.setUsername("root");
        reqDTO.setPassword("000000");

        UserServiceImpl userService = new UserServiceImpl();
        log.info("return---->{}", userService.register(reqDTO));
    }

RegisterInterceptor

import com.liyulin.bytebuddy.dto.RegisterReqDTO;
import com.liyulin.bytebuddy.service.impl.UserServiceImpl;
import net.bytebuddy.implementation.bind.annotation.*;
import java.util.concurrent.Callable;

public class RegisterInterceptor {
    @RuntimeType
    public static Object intercept(@This Object target, @Argument(0) RegisterReqDTO reqDTO, @Morph UserServiceImpl userService,
                                   @SuperCall Callable<?> call) throws Exception {
        // 1.do something
        // ......

        // 2.call target method
        return call.call();
    }
}

luckyQing avatar Aug 28 '24 02:08 luckyQing

For using @Morph, you need to install a binder: https://github.com/raphw/byte-buddy/blob/master/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Morph.java#L153

raphw avatar Aug 29 '24 07:08 raphw

@raphw I copied an incorrect RegisterInterceptor. My real code looks like this:

public class RegisterInterceptor {
    public static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RegisterInterceptor.class);
    @RuntimeType
    public static Object intercept(@Argument(0) RegisterReqDTO reqDTO, @SuperCall Callable<?> call) throws Exception {
        log.info("intercept---->{}", reqDTO);
        // 1.do something
        // ......

        // 2.call target method
        return call.call();
    }
}

Test case:

    @Test
    public void testInterceptor() {
        ByteBuddyAgent.install();
        new ByteBuddy()
                .redefine(UserServiceImpl.class)
                .method(named("register"))
                .intercept(MethodDelegation.to(RegisterInterceptor.class))
                .make()
                .load(UserServiceImpl.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

        RegisterReqDTO reqDTO = new RegisterReqDTO();
        reqDTO.setUsername("root");
        reqDTO.setPassword("000000");

        UserServiceImpl userService = new UserServiceImpl();
        log.info("return---->{}", userService.register(reqDTO));
    }

The error info: java.lang.IllegalArgumentException: None of [public static java.lang.Object com.demo.bytebuddy.advice.RegisterInterceptor.intercept(com.demo.bytebuddy.dto.RegisterReqDTO,java.util.concurrent.Callable) throws java.lang.Exception] allows for delegation from public com.demo.bytebuddy.dto.RegisterRespDTO com.demo.bytebuddy.service.impl.UserServiceImpl.register(com.demo.bytebuddy.dto.RegisterReqDTO)

luckyQing avatar Aug 29 '24 08:08 luckyQing

We also started to see this error with spring boot 3.3.3 dependency update that bumps bytebuddy to 1.14.19 from 1.14.18 (https://github.com/spring-projects/spring-boot/commit/2af1afbe4fe5ae49991cb77f5d6dcefd884601d9)

bduisenov avatar Sep 02 '24 15:09 bduisenov

This might relate to a clean up I did with regards to method visibility. There is a check for visibility and accessibility. The errors here can be rather subtle. Typically, the delegated type should be public and the method, too.

To debug this, you can set a breakpoint in MethodDelegation::append and see what methods are considered. To understand what is wrong, I normally need a reproducer of some kind.

raphw avatar Sep 02 '24 20:09 raphw

thanks @raphw, defining an interceptor class as public instead of protected solved the issue.

~~protected~~ public static class SomeInterceptor {

        @RuntimeType
        public static void intercept(@This Object object, @Origin Method setter) {
            ...
        }
    }

bduisenov avatar Sep 24 '24 09:09 bduisenov