jeudi 11 janvier 2018

Use LambdaMetafactory.metafactory() for plain non-static getter

I have a simple Person class with a getName() that returns a String:

public class Person {

    public String getName() {...}

}

How do I use LambdaMetafactory to create a lamdba for that at runtime?


Here's what I got this far:

public static void main(String[] args) {
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodType invokedType = MethodType.methodType(GetterFunction.class);
    MethodType methodType = MethodType.methodType(Object.class);
    MethodType actualMethodType = MethodType.methodType(String.class);
    CallSite site;
    try {
        MethodHandle virtual = lookup.findVirtual(Person.class, "getName", actualMethodType);
        site = LambdaMetafactory.metafactory(lookup,
                "getName",
                invokedType,
                methodType,
                virtual,
                methodType);
    } catch (LambdaConversionException | NoSuchMethodException | IllegalAccessException e) {
        throw new IllegalArgumentException(e);
    }

    GetterFunction getterFunction;
    try {
        getterFunction = (GetterFunction) site.getTarget().invokeExact();
    } catch (Throwable e) {
        throw new IllegalArgumentException(e);
    }
    System.out.println(getterFunction.getName(new Person("Ann")));
}

@FunctionalInterface
private interface GetterFunction {

    String getName(Person person);

}

Which throws:

java.lang.invoke.LambdaConversionException: Incorrect number of parameters for instance method invokeVirtual foo.Person.getName:()String; 0 captured parameters, 0 functional interface method parameters, 0 implementation parameters
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:193)
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)





Aucun commentaire:

Enregistrer un commentaire