Skip to content

LambdaMetafactory

Brian S. O'Neill edited this page Dec 24, 2024 · 9 revisions

The LambdaMetafactory class is used to bootstrap dynamic methods for Java lambda functions. It's one of the more complex features of the "indy" framework, but this example provides a starting point.

Consider this Java code which invokes a lambda function:

    public void hello() {
        exec(() -> {
            System.out.println("hello, world");
        });
    }

    private static void exec(Runnable r) {
        r.run();
    }

The Java compiler desugars the hello method into this:

    public void hello() {
        // Use LambdaMetafactory to define an implementation of Runnable, which
        // is then passed to the exec method. One of the bootstrap parameters
        // refers to the generated "lambda$hello$0" delegate method.
        exec(InvokeDynamic #0:run:()Ljava/lang/Runnable;)
    }

    private static void lambda$hello$0() {
        System.out.println("hello, world");
    }

The following code generates a complete class which can run the example.

        ClassMaker cm = ClassMaker.begin().public_();

        // Need a default constructor.
        cm.addConstructor().public_();

        // Define a private "exec" method which takes a Runnable.
        {
            MethodMaker mm = cm.addMethod(void.class, "exec", Runnable.class).private_().static_();
            mm.param(0).invoke("run");
        }

        // Define a private "desugared" lambda implementation method. Mark it as synthetic to help
        // Java decompilers understand what's going on.
        {
            MethodMaker mm = cm.addMethod(void.class, "lambda$hello$0").private_().static_().synthetic();
            mm.var(System.class).field("out").invoke("println", "hello, world");
        }

        // Define a public method which invokes a lambda function...

        MethodMaker mm = cm.addMethod(void.class, "hello").public_();

        // LambdaMetafactory stuff...
        MethodType mt = MethodType.methodType(void.class);
        var implMethod = mm.this_().methodHandle(void.class, "lambda$hello$0");
        var bootstrap = mm.var(LambdaMetafactory.class).indy("metafactory", mt, implMethod, mt);
        // Note: Extra params are needed if lambda implementation method isn't static.
        var function = bootstrap.invoke(Runnable.class, "run"); // , null, mm.this_());

        // Invoke the Runnable function.
        mm.invoke("exec", function);

        // Finish the class and run it.

        var clazz = cm.finish();
        var instance = clazz.getConstructor().newInstance();
        clazz.getMethod("hello").invoke(instance);
Clone this wiki locally