mercredi 5 juillet 2017

Chain/transform method calls with ByteBuddy

Using ByteBuddy, can I implement one instance method by calling another and transforming the result?

For instance (toy example):

public abstract class Foo {
  public String bar() {
    return "bar";
  }

  public abstract int baz();
}

Given the above, can I implement baz such that it calls bar() and returns the length of the returned string?

Naively, I tried the following:

Method bar = Foo.class.getDeclaredMethod("bar");
Method baz = Foo.class.getDeclaredMethod("baz");

Method length = String.class.getDeclaredMethod("length");

Foo foo = new ByteBuddy()
  .subclass(Foo.class)
  .method(ElementMatchers.is(baz))
  .intercept(
    MethodCall.invoke(bar)                 // call bar()...
      .andThen(MethodCall.invoke(length))  // ... .length()?
  ).make()
  .load(Foo.class.getClassLoader())
  .getLoaded()
  .newInstance();

System.out.println(foo.baz());

However, it looks like I was wrong in thinking andThen() is invoked on the return value of the first invocation; it looks like it's invoked on the generated instance?

Exception in thread "main" java.lang.IllegalStateException: 
  Cannot invoke public int java.lang.String.length() on class Foo$ByteBuddy$sVgjXXp9
    at net.bytebuddy.implementation.MethodCall$MethodInvoker$ForContextualInvocation.invoke(MethodCall.java:1667)

How can I get ByteBuddy to invoke one method and then invoke another on its return value?





Aucun commentaire:

Enregistrer un commentaire