3

I want to generate byte code of a class which passes a method reference as argument to another method. e.g.:

public class GeneratedClass {
    public GeneratedClass() {
        Test.foo((Function)Test::getId)
    }
}

Using ByteBuddy I can generate a class with custom constructor, and create an InvokeDynamic to represent the Test::getId, but the problem is that I cannot pass the InvokeDynamic as a parameter to my MethodCall. My current implementation is as follows:

var fooMethod = Test.class.getMethod("foo",Function.class);
InvokeDynamic methodRef = InvokeDynamic.lambda(Test.class.getMethod("getId"), Function.class)
        .withoutArguments();
new ByteBuddy()
        .subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
        .name("GeneratedClass")
        .defineConstructor(Visibility.PUBLIC)
        .intercept(
                MethodCall.invoke(fooMethod)
                .with((Object)null) \\I want to pass the methodRef instead of null
                .andThen(methodRef)
        ).make()
        .saveIn(new File("target"));

Which generates the following:

public class GeneratedClass {
    public GeneratedClass() {
        Test.foo((Function)null);
        Test::getId;
    }
}
Rasoul
  • 53
  • 1
  • 5

1 Answers1

2

As of today, this is not supported by the DSL but you can supply a custom StackManipulation as an argument to with. In your case, you would need to resolve a MethodInvocation for this.

With a little trick, you can however implement this today but creating a helper method:

builder = builder
  .defineMethod("mylambda", Function.class, Visibility.PRIVATE, Ownership.STATIC)
  .intercept(methodRef)

You can then call this method using a MethodCall and pass it as an argument.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Thanks for your answer! Reading the documentation, I cannot figure out how to do it using `StackManipulation`, Would you please produce a code example? – Rasoul May 11 '21 at 13:12