Явное использование LambdaMetafactory

Я пытаюсь явно использовать LambdaMetafactory.metafactory, я не могу понять, почему он работает только с функциональным интерфейсом Runnable. Например, этот код делает то, что ожидается (он выводит «hello world»):

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(void.class);
        MethodType invokedType = MethodType.methodType(Runnable.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "run", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", methodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Runnable r = (Runnable) factory.invoke();
        r.run();
    }

    private static void print() {
        System.out.println("hello world"); 
    }    
}

Проблема возникает, когда я пытаюсь использовать другой функциональный интерфейс, например, поставщик. Следующий код не работает:

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(String.class);
        MethodType invokedType = MethodType.methodType(Supplier.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "get", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", methodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Supplier<String> r = (Supplier<String>) factory.invoke();
        System.out.println(r.get());        
    }
    private static String print() {
        return "hello world";
    }    
}


Exception in thread "main" java.lang.AbstractMethodError: metafactorytest.MetafactoryTest$Lambda$1/258952499.get()Ljava/lang/Object;
    at metafactorytest.MetafactoryTest.main(MetafactoryTest.java:29)

Разве два фрагмента кода не должны работать одинаково, что является проблемой во втором фрагменте кода?

Кроме того, следующий код, который должен быть эквивалентен, работает хорошо:

public class MetafactoryTest {

    public static void main(String[] args) throws Throwable {
        Supplier<String> r = (Supplier<String>) () -> print();
        System.out.println(r.get());        
    }

    private static String print() {
        return "hello world";
    }    
}

редактировать

Другое решение, которое позволяет избежать изменения типа возврата метода, заключается в определении нового функционального интерфейса:

public class MetafactoryTest {

    @FunctionalInterface
    public interface Test {
        String getString();
    }

    public static void main(String[] args) throws Throwable {

        MethodHandles.Lookup caller = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(String.class);
        MethodType invokedType = MethodType.methodType(Test.class);
        CallSite site = LambdaMetafactory.metafactory(caller, 
                                                      "getString", 
                                                      invokedType, 
                                                      methodType, 
                                                      caller.findStatic(MetafactoryTest.class, "print", methodType), 
                                                      methodType);
        MethodHandle factory = site.getTarget();
        Test r = (Test) factory.invoke();
        System.out.println(r.getString());        
    }

    private static String print() {
        return "hello world";
    }  

Ответы на вопрос(2)

Ваш ответ на вопрос