ardalan foroughi pour
ardalan foroughi pour

Reputation: 83

Invoking a method in super class that has been overriden in ByteBuddy using ElementMatchers

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

Answers (1)

Rafael Winterhalter
Rafael Winterhalter

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

Related Questions