Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Generic Return type of a method using Reflections

Is there a way get the return type of a generic method- return type?

public interface MyGeneric<T> {
  T doSomething();
}

public interface MyElement extends MyGeneric<Element> {

}

public class Main {
  public static final void main(String[] args) {
    System.out.println(MyElement.class.getMethod("doSomething", new Class<?>[0]).magic()); // => Element
  }
}

Using Method.getReturnType() I get java.lang.Object without. Does the method "magic" exist?

like image 879
mibutec Avatar asked Nov 11 '13 12:11

mibutec


People also ask

How do you find the type of generic class?

If we want the actual type of a generic parameter, we should inject it to the class in another way (e.g. constructor parameter, abstract function that returns the actual type, etc...).

What are generic methods generic methods are the methods defined in a generic class?

Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.

How do you declare a generic method How do you invoke a generic method?

Generic MethodsAll generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E > in the next example). Each type parameter section contains one or more type parameters separated by commas.


2 Answers

Unfortunately, the reflection capabilities in the core Java library are rather poor for analyzing generic types. You can use the getGeneric... methods (e.g., getGenericReturnType()), but they don't work all that well, and they usually return Type instances instead of Class instances. I find this very clumsy to work with.

I have written my own reflection API, based the .NET's, which I feel is more consistent (particularly where generics are concerned). Consider the following output:

import com.strobel.reflection.Type;

interface MyGeneric<T> {
    T doSomething();
}

interface Element {}

interface MyElement extends MyGeneric<Element> {}

class Main {
    public static final void main(String[] args) throws NoSuchMethodException {
        // prints "class java.lang.Object":
        System.out.println(
            MyElement.class.getMethod("doSomething").getReturnType()
        );
        // prints "T":
        System.out.println(
            MyElement.class.getMethod("doSomething").getGenericReturnType()
        );
        // prints "Element":
        System.out.println(
            Type.of(MyElement.class).getMethod("doSomething").getReturnType()
        );
    }
}

You're welcome to use my library. I actually just committed a bug fix that prevented this example from working (it's in the tip of the develop branch).

like image 103
Mike Strobel Avatar answered Sep 28 '22 12:09

Mike Strobel


No, that magic does not exist generally. If you want to make a trick in order to get to that data, you can require that data in your interface like explained here.

On the other side, if your type is special (like a List), you can do that. See this answer for special types.

like image 41
V G Avatar answered Sep 28 '22 12:09

V G