Reputation: 83
I want to dynamically create classes like this in bytebuddy
public class Parent {
public boolean testMethod(int n){
return true;
}
}
public class Child extends Parent{
@Override
public boolean testMethod(int n) {
return false;
}
public boolean testMethodSuperWrapper(int n){
return super.testMethod(n);
}
}
the code that I am writing is like this:
Class parentClass = new ByteBuddy().subclass(Object.class).name("Parent")
.defineMethod("testMethod", boolean.class, Modifier.PUBLIC)
.withParameter(int.class).intercept(FixedValue.value(true))
.make().load(Test.class.getClassLoader()).getLoaded();
Class childClass = new ByteBuddy().subclass(parentClass).name("Child")
.defineMethod("testMethod", boolean.class, Modifier.PUBLIC)
.withParameter(int.class).intercept(FixedValue.value(false))
.defineMethod("testMethodSuperWrapper", boolean.class, Modifier.PUBLIC)
.withParameters(int.class).intercept(MethodCall.invoke(
ElementMatchers.isMethod()
.and(ElementMatchers.hasMethodName("testMethod"))
.and(ElementMatchers.takesArguments(int.class))
//.and(ElementMatchers.isDeclaredBy(parentClass))
)
.onSuper()
.withAllArguments())
.make().load(parentClass.getClassLoader()).getLoaded();
Object childClassObject = childClass.newInstance();
Method superWrapperMethod = childClass.getMethod("testMethodSuperWrapper", int.class);
boolean res = (boolean) superWrapperMethod.invoke(childClassObject, 23);
System.out.println(res);
I know I can use the Method
class to make testMethodSuperWrapper
invoke the parent method but for reasons in my project (cyclic types) I need to create testMethodSuperWrapper
invoke the testMethod
in the parent class using ElementMatchers.
The problem is when I use ElementMatchers to invoke the method in parent class like in my code I get this error: Cannot invoke public boolean Child.testMethod(int) as super method of class Child
.
Also if I comment the .onSuper()
line and uncomment the .and(ElementMatchers.isDeclaredBy(parentClass))
I would get this error instead class Child does not define exactly one virtual method or constructor for (isMethod() and name(equals(testMethod)) and hasParameter(hasTypes(erasures(containing(is(int))))) and declaredBy(erasure(is(class Parent)))) but contained 0 candidates: []
Upvotes: 1
Views: 571
Reputation: 44007
This has to do with Byte Buddy's internal model where you replace a method that is defined by the super type, rather then overriding it. In Java this is really the same, but in Byte Buddy, it is (unfortunately) not.
You can override a method by matching it, rather then defining it as in:
new ByteBuddy().subclass(parentClass).name("Child")
.method(ElementMatchers.named("testMethod"))
.intercept(FixedValue.value(false))
This way, your override will work.
Upvotes: 1