dimanche 14 mai 2017

Java8 retrieving lambda setter from class

I'm trying to get a lambda method handle for the setter of a private field, but for some reason, the setter cannot be found.

This is the functional interface I am using:

@FunctionalInterface
public interface ISetter<T, R> {
    void set(T object, R value);
}

And this the method used to fetch the setter:

public ISetter getSetter(Class clazz, String fieldName, Class fieldType) throws Throwable {

    MethodHandles.Lookup caller = MethodHandles.lookup();
    MethodType setter = MethodType.methodType(Void.class, fieldType);
    MethodHandle target = caller.findVirtual(clazz, computeSetterName(fieldName), setter);
    MethodType func = target.type();

    CallSite site = LambdaMetafactory.metafactory(
            caller,
            "set",
            MethodType.methodType(ISetter.class),
            func.generic(),
            target,
            func
    );

    MethodHandle factory = site.getTarget();
    ISetter r = (ISetter) factory.invoke();

    return r;
}

All setters are, by convention, named the same: "setField(...)". This is my test class:

public class TestEntity {

    private Long id;


    public TestEntity(Long id) {
        this.id = id;
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

But when I execute this method for "id" and "Long.class" I get the follow exception:

Exception in thread "main" java.lang.NoSuchMethodException: no such method: de.cyclonit.exercise.TestEntity.setId(Long)Void/invokeVirtual
    at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1003)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1381)
    at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:859)
    at de.cyclonit.exercise.AccessorFactory.getSetter(AccessorFactory.java:41)
    at de.cyclonit.exercise.Main.main(Main.java:21)
Caused by: java.lang.NoSuchFieldError: method resolution failed
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:975)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1000)
    ... 4 more

I don't understand where this error is coming from. The method "void setId(Long)" does exist.





Aucun commentaire:

Enregistrer un commentaire