即使方法被调用一次,方法也被拦截了两次
Method intercepted twice even though it was called once
在下面的代码片段中,我在 Subclass
的实例上调用方法 doStuff
一次。然而它被拦截了两次。
请注意,doStuff
是在父 class SuperClass
中定义的。如果 doStuff
在 SubClass
中定义,拦截逻辑将按预期工作:只有一次拦截。
我是不是用错了字节好友?
package com.test;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import java.util.concurrent.Callable;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import org.junit.Test;
public class ReproBugTest {
@Test
public void reproBug() {
new AgentBuilder.Default().type(nameStartsWith("com.test"))
.transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(
Builder<?> builder,
TypeDescription td) {
return builder.method(any())
.intercept(
MethodDelegation.to(MethodInterceptor.class));
}
})
.installOn(
ByteBuddyAgent.installOnOpenJDK());
SubClass subClass = new SubClass();
subClass.doStuff();
}
}
class SuperClass {
public void doStuff() {
System.out.println("Doing stuff...");
}
}
class SubClass extends SuperClass {
}
class MethodInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper)
throws Exception {
// Intercepted twice, bug?
System.out.println("Intercepted");
Object returnValue = zuper.call();
return returnValue;
}
}
您正在拦截每种类型的方法调用,即 Subclass
和 SuperClass
。您需要进一步指定拦截器拦截哪些方法。在您的情况下,您只想拦截由给定类型声明的方法。
这很容易实现。你应该截取 builder.method(isDeclaredBy(td))
而不是 builder.method(any())
。这样,只有被拦截类型声明的方法才会被拦截。
最后,我可以从您的源代码中看出您使用的是旧版本的 Byte Buddy。版本 0.7-rc6 运行稳定,具有附加功能并修复了几个错误。 (不过,部分API仍需更改。)
在下面的代码片段中,我在 Subclass
的实例上调用方法 doStuff
一次。然而它被拦截了两次。
请注意,doStuff
是在父 class SuperClass
中定义的。如果 doStuff
在 SubClass
中定义,拦截逻辑将按预期工作:只有一次拦截。
我是不是用错了字节好友?
package com.test;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import java.util.concurrent.Callable;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import org.junit.Test;
public class ReproBugTest {
@Test
public void reproBug() {
new AgentBuilder.Default().type(nameStartsWith("com.test"))
.transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(
Builder<?> builder,
TypeDescription td) {
return builder.method(any())
.intercept(
MethodDelegation.to(MethodInterceptor.class));
}
})
.installOn(
ByteBuddyAgent.installOnOpenJDK());
SubClass subClass = new SubClass();
subClass.doStuff();
}
}
class SuperClass {
public void doStuff() {
System.out.println("Doing stuff...");
}
}
class SubClass extends SuperClass {
}
class MethodInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper)
throws Exception {
// Intercepted twice, bug?
System.out.println("Intercepted");
Object returnValue = zuper.call();
return returnValue;
}
}
您正在拦截每种类型的方法调用,即 Subclass
和 SuperClass
。您需要进一步指定拦截器拦截哪些方法。在您的情况下,您只想拦截由给定类型声明的方法。
这很容易实现。你应该截取 builder.method(isDeclaredBy(td))
而不是 builder.method(any())
。这样,只有被拦截类型声明的方法才会被拦截。
最后,我可以从您的源代码中看出您使用的是旧版本的 Byte Buddy。版本 0.7-rc6 运行稳定,具有附加功能并修复了几个错误。 (不过,部分API仍需更改。)