wolfram77 wolfram77 - 1 year ago 114
Java Question

How can I create a Functional interface implementation for Fields?

Consider a field

in class
. I want to be able to create a getter and setter functional interface objects for manipulating this field.

class Animal {
int weight;

My current approach is similar to one used for methods:

public static Supplier getter(Object obj, Class<?> cls, Field f) throws Exception {
boolean isstatic = Modifier.isStatic(f.getModifiers());
MethodType sSig = MethodType.methodType(f.getType());
Class<?> dCls = Supplier.class;
MethodType dSig = MethodType.methodType(Object.class);
String dMthd = "get";
MethodType dType = isstatic? MethodType.methodType(dCls) : MethodType.methodType(dCls, cls);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle fctry = LambdaMetafactory.metafactory(lookup, dMthd, dType, dSig, lookup.unreflectGetter(f), sSig).getTarget();
fctry = !isstatic && obj!=null? fctry.bindTo(obj) : fctry;
return (Supplier)fctry.invoke();

But this gives the following error:

java.lang.invoke.LambdaConversionException: Unsupported MethodHandle kind: getField x.Animal.weight:()int

Answer Source

You can directly write the lambda, you don't need the LambdaMetafactory at all:

public static Supplier getter(Object obj, Field f) {
    return () -> {
        try {
            return f.get(obj);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);

Or a runtime-typesafe version:

public static <T> Supplier<T> getter(Object obj, Class<T> fieldClass, Field f) {

    if (!fieldClass.isAssignableFrom(f.getType()))
        throw new RuntimeException("Field is not of expected type");

    return () -> {
        try {
            return (T) f.get(obj);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);


private class X {
    public int a;

public void supplier_getter_test() throws NoSuchFieldException {
    X a = new X();
    a.a = 5;

    Supplier<Integer> sup = getter(a, int.class, X.class.getField("a"));

    assertEquals(5, sup.get().intValue());