0

My goal is to create a MethodHandle that, by passing a class and a field name, reads that field with a MethodHandle getter and returns the value.

With this method I wanted to return an arbitrary object:

return new ConstantCallSite(MethodHandles.lookup().unreflectGetter(f).asType(MethodType.methodType(Object.class))).dynamicInvoker();

I received the Field f via Reflections. The problem now is that when this method is executed, the typical error for invokeExact (WrongMethodTypeException) occurs:

WrongMethodTypeException: cannot convert MethodHandle(TestClass)String to ()Object

This also applies to ints, floats, etc. In another thread I also already read that you can use invokeExact dynamically if the return of MethodHandle is changed to Object. Here is a code snippet from the method, which makes use of passing a static final MethodHandle:

return (T) handle.invokeExact(testObject);

Using MethodHandle#invoke is rather out of the question for me, as I'm after performance. Without invokeExact I could possibly also fall back on using only reflections.

Does anyone know a way to do this or a workaround with similar performance? The latter plays a big role in the project. I thank those in advance who could possibly help with this problem.

evolnior
  • 3
  • 1

1 Answers1

1

A (non-static) getter needs an instance to retrieve the field's value from. You should be able to make this work by adding another Object parameter to the erased method type:

return MethodHandles.lookup().unreflectGetter(f).asType(MethodType.methodType(Object.class, Object.class));

(Also, there's no need to wrap the thing in a ConstantCallsite)

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
  • Oh, I didn't know that an instance is already required there. Thanks a lot! Also, I thought that with `ConstantCallsite` the target field is finalized, so this is also optimized once again. Is that not the case? – evolnior Aug 31 '22 at 21:37
  • @evolnior Not sure what you mean by "finalized". But if you look at the `ConstantCallSite::dynamicInvoker` method, you'll see that it just returns the target handle that you pass to the constructor. – Jorn Vernee Aug 31 '22 at 21:44
  • Ah I see... I should have checked again myself. Thank you very much! – evolnior Aug 31 '22 at 22:03
  • 1
    @evolnior I wonder what you mean with “*that an instance is already required there*”. The method type describes how the invocation, which may be arbitrarily far in the future, will look like. And since your invocation looks like `handle.invokeExact(testObject)`, there obviously *is* an object argument provided, so the handles type also must have a parameter. Even if you forgot that a handle to a field getter has an `Object → value` signature, the final invocation in your code also expects an `Object → Object` signature, regardless of where the handle came from. – Holger Nov 29 '22 at 16:25