-
-
Notifications
You must be signed in to change notification settings - Fork 828
Open
Labels
Description
Description:
I am learning ByteBuddy and encountered an issue while trying to use MethodDelegation
to intercept a method. Below is my full demo:
import net.bytebuddy.ByteBuddy
import net.bytebuddy.agent.ByteBuddyAgent
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy
import net.bytebuddy.implementation.MethodDelegation
import net.bytebuddy.implementation.bind.annotation.RuntimeType
import net.bytebuddy.implementation.bind.annotation.SuperCall
import net.bytebuddy.matcher.ElementMatchers
import java.util.concurrent.Callable
class InnerRequest {
fun request(message: String) {
println(message)
}
}
class CustomRequest {
fun request() {
val message = "secret String"
InnerRequest().request(message)
}
}
class RequestInterceptor {
companion object {
@JvmStatic
fun intercept(@RuntimeType message: String, @SuperCall zpuer: Callable<Any>) {
println("Get secret message: $message")
zpuer.call()
}
}
}
fun main() {
ByteBuddyAgent.install()
ByteBuddy()
.redefine(InnerRequest::class.java)
.method(ElementMatchers.named("request"))
.intercept(MethodDelegation.to(RequestInterceptor::class.java))
.make()
.load(
InnerRequest::class.java.classLoader,
ClassReloadingStrategy.fromInstalledAgent()
)
CustomRequest().request()
}
When I run this code, I get the following error:
Exception in thread "main" java.lang.IllegalArgumentException: None of [public static final void RequestInterceptor.intercept(java.lang.String,java.util.concurrent.Callable)] allows for delegation from public final void InnerRequest.request(java.lang.String)
I understand that this error occurs because the interceptor method's signature does not match the intercepted method's signature.
To address this, I tried using Advice
instead of MethodDelegation
, and it worked perfectly. Here is the working version with Advice
:
class RequestAdvice {
companion object {
@JvmStatic
@Advice.OnMethodEnter
fun enter(@Advice.Argument(0) message: String) {
println("Get secret message: $message")
}
}
}
fun main() {
ByteBuddyAgent.install()
ByteBuddy()
.redefine(InnerRequest::class.java)
.visit(
Advice.to(RequestAdvice::class.java)
.on(ElementMatchers.named("request"))
)
.make()
.load(
InnerRequest::class.java.classLoader,
ClassReloadingStrategy.fromInstalledAgent()
)
CustomRequest().request()
}
This approach works as expected, and the output is:
Get secret message: secret String
secret String
However, I want to achieve the same functionality using MethodDelegation
instead of Advice
. How can I modify my interceptor and MethodDelegation
logic to make it work?
Additional Notes:
- I understand that the
MethodDelegation
signature must match the intercepted method's signature (including parameters, return type, and static/non-static nature). - I want to keep the ability to access the method argument (
message
) and optionally call the original method (like@SuperCall
does).
Any help would be greatly appreciated.