0

I need to call the getName() method of a Person class, without knowing the Person class as compilation time and by using a MethodHandle (instead of normal reflection).

So I'd want this code to work (this code cannot change):

MyGetterAccessor myGA = new MyGetterAccessor(Person.class, "getName", String.class)
assertEquals("Ann", myGA.call(new Person("Ann"));
assertEquals("Beth", myGA.call(new Person("Beth"));

Here's my method handle code, which must not use the word "Person" (this can can change to make this work):

public class MyGetterAccessor {

    MethodHandle mh;

    public GetterAccessor(Class entityClass, String methodName, Class returnType) {
        mh = MethodHandles.lookup().findVirtual(entityClass, methodName, MethodType.methodType(returnType));
    }

    public Object call(Object entity) {
        return mh.invokeExact(entity);
    }

}

but this fails with WrongMethodTypeException. Any suggestion how to fix that?

Holger
  • 285,553
  • 42
  • 434
  • 765
Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120

2 Answers2

0

Maybe

public static <T,R> setValue(T setTo, BiFunction<T,String,R> setter, String value) {
    return setter.apply(setTo, value);
}

assertEquals("Ann", setValue(new Person(), Person::set, "Ann"));

Or is that not reflective enough?

daniu
  • 14,137
  • 4
  • 32
  • 53
  • 1
    The `MyGetterAccessor` needs to call the `Person.getName()` method and the `main()` method should be exactly as it is stated above (it can't not be required to pass lamba's for the getter/setter, the method name should be enough). So sorry, not reflective enough... – Geoffrey De Smet Dec 21 '17 at 15:00
0

FWIW, this works, but it's slow in java 8 in my benchmarks.

MethodHandle temp = lookup.findVirtual(getterMethod.getDeclaringClass(), getterMethod.getName(), MethodType.methodType(returnType));
temp = temp.asType(temp.type().changeParameterType(0 , Object.class));
getterMethodHandle = temp.asType(temp.type().changeReturnType(Object.class));
Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120
  • Mind the existence of [`MethodType.erase()`](https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodType.html#erase--) which makes it much easier to replace all reference types with `Object`. – Holger Jun 13 '18 at 07:33