Express a general `MethodType` with return type as any object

655 Views Asked by At

Let the following be a class in my problem:

class MyClass {
    String name() {
        return toString();
    }
}

I want to create an instance of MethodType which describes a method with a return that is "any" object. I am trying the following:

MethodType genericTypeWithObjectReturn = 
    MethodType.methodType(Object.class, new Class[] {});

then try to find a method using

MethodHandle mh = 
    lookup.findVirtual(MyClass.class, "name", genericTypeWithObjectReturn);

Using the above line, I get an exception:

Caused by: java.lang.NoSuchMethodError: MyClass.name()Ljava/lang/Object;

My observation is that the method return type should be exactly the same type; namely I should have used String.class in the above statement to define MethodType. Is this correct? Is there a way so that I can do this in the way I described and preferrably not using reflection API?

3

There are 3 best solutions below

0
On

yes. you should use String.class for resolving right method type. as i know you can't implement it with method handles api, but you can use Reflection API.

0
On

There's no way to use the find{Virtual,Static} methods to get method handles without specifying the exact method type, including the return type. This is a consequence of the JVM allowing overloading on return type, even though the Java programming language does not. From the documentation for Class.getMethod (emphasis mine):

To find a matching method in a class or interface C: If C declares exactly one public method with the specified name and exactly the same formal parameter types, that is the method reflected. If more than one such method is found in C, and one of these methods has a return type that is more specific than any of the others, that method is reflected; otherwise one of the methods is chosen arbitrarily.

Note that there may be more than one matching method in a class because while the Java language forbids a class to declare multiple methods with the same signature but different return types, the Java virtual machine does not. This increased flexibility in the virtual machine can be used to implement various language features. For example, covariant returns can be implemented with bridge methods; the bridge method and the method being overridden would have the same signature but different return types.

Thus JVM methods can be made inaccessible to Class.getMethod by the presence of other methods with the same signature but different (not-more-specific) return types. Given that the purpose of method handles is to support other languages on the JVM, including languages that either support overloading on return type in the source or that generate return type overloads as part of mapping to the JVM, this hole had to be fixed by requiring the exact type to be specified. (You could imagine a method pow(int, int) with overloads returning int, long, and BigInteger, selected by the source language based on the context type in foo(pow(1000, 100000));.)

Apart from that hard requirement to make all methods accessible, it's arguably better from an API design standpoint to fail fast if the desired method is not found rather than silently select an argument-compatible but different method.


If you're happy with the lookup semantics of Class.getMethod, you can use it and call MethodHandles.Lookup.unreflect on the returned Method.

0
On

since an answer is still missing...

The MethodType has to be exact. That's a big pain point in the MethodHandles-API, but only because you control the transformation are some of the optimizations possible. The solution is to use reflection to find the method and then use MethodHandles#unreflect* to get the handle.