[Question] How do I call an intercepted method in an interceptor?
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();
}
}
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 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)
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)
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.
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) {
...
}
}