Search code examples
byte-buddy

Referring to a dynamically added method in ByteBuddy AgentBuilder


I want to achieve the following scenario using Byte Buddy

  1. Define a new constructor in an abstract class
  2. Create a new method in a subtype that invokes #1 However I am running into an issue where the transformer for #2 is not able to find the method defined in #1.

A more detailed description of the setup is as follows:

I have classes Base and A

public abstract class Base {
  protected Base() {}
  protected Base(String s, Object o) {...}
}
public abstract class A {
  protected A() {}
}

I want to add another constructor to A equivalent to

  protected A(String s, Integer i) {
    super(s, i);
  }

So I wrote

new AgentBuilder.Default().type(named("A"))
  .transform((builder, typeDescription, classLoader, module) ->

    builder.defineConstructor(Visibility.PROTECTED)
        .withParameter(String.class)
        .withParameter(Integer.class)
        .intercept(
            MethodCall.invoke(isConstructor().and(takesArguments(String.class, Object.class)))
              .withArgument(0, 1)))
  .installOn(instrumentation);

If I run my code with this agent, I am able to see the new constructor added at runtime.

Now I want to reference this newly added constructor in another class B.

public class B extends A {

   // I want to add this method
   newMethod() {
     super("str", 0)
   }
}

So I wrote

new AgentBuilder.Default().type(isSubTypeOf(A.class)))
  .transform((builder, typeDescription, classLoader, module) ->

    builder.defineMethod("newMethod", typeDescription, Visibility.PUBLIC)
      .intercept(
          MethodCall.invoke(isConstructor().and(takesArguments(String.class, Integer.class)))
            .with("str")
            .with(0)))
  .installOn(instrumentation);

However, I receive an error like below

java.lang.IllegalStateException: class B does not define exactly one virtual method or constructor for (isConstructor() and hasParameter(hasTypes(erasures(containing(is(class String), is(class Integer)))))) but contained 0 candidates: []

Can I not reference a method which I added in a previous transformer? (First-time ByteBuddy user)


Solution

  • The problem is that the other class needs to be located from the class path where the stored class file is represented in the old format. Instead of using a matcher which implicitly browses the hierarchy, rather supply the method explicitly, for example by using a MethodDescription.Latent.