Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different return type of generic method depending on invocation location

Tags:

java

generics

I have the following method with generics that executes the getter of each item in the list it receives:

public static <T, S> List<S> getValues(List<T> list, String fieldName) {
    List<S> ret = new ArrayList<S>();
    String methodName = "get" + fieldName.substring(0, 1).toUpperCase()
            + fieldName.substring(1, fieldName.length());
    try {
        if (list != null && !list.isEmpty()) {
            for (T t : list) {
                ret.add((S) t.getClass().getMethod(methodName).invoke(t));
            }
        }
    } catch (IllegalArgumentException e) {
    } catch (SecurityException e) {
    } catch (IllegalAccessException e) {
    } catch (InvocationTargetException e) {
    } catch (NoSuchMethodException e) {
    }
    return ret;
}

It works perfectly fine if I call it as this:

List<Integer> ids = getValues(List<MyDTO>, "id");
request.setListIds(ids);

But, it gives me a compile error if I do it in a single line:

request.setListIds(getValues(List<MyDTO>, "id"));

The error says:

The method setListIds(List-Integer-) in the type MyDTO is not applicable for the arguments (List-Object-)

So, when I try to directly set the list, it is casting the generic to Object instead of Integer. Why is that?

like image 642
Luis Sep Avatar asked Nov 12 '13 11:11

Luis Sep


People also ask

How does a generic method differ from a generic type?

From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.

Can Java return type be generic?

So methods of generic or nongeneric classes can use generic types as argument and return types as well. Here are examples of those usages: // Not generic methods class GenericClass < T > { // method using generic class parameter type public void T cache ( T entry ) { ... } }

What is the correct way of defining a generic method?

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.


2 Answers

It is due to Java's quite weak type inference. It can infer the type when you directly assign to a variable, but it won't infer by the target argument type, which you need in the second example.

You can overcome this with this.<Integer>getValues...

like image 129
Marko Topolnik Avatar answered Sep 21 '22 05:09

Marko Topolnik


Apparently the compiler is not correctly guessing the generic type variables. In the assigment, he correctly guesses S=Integer, while when passing the result as parameter, it is not taking into account the generic type of the method parameter.

This is because of type-erasure, since the signature of the method at runtime is setListIds(List), not setListIds(List<Integer>). By the way the same question was asked here, and the answer explains why the compiler behaves like that.

like image 33
kutschkem Avatar answered Sep 21 '22 05:09

kutschkem