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?
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.
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 ) { ... } }
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.
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...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With