I have a POJO specified as: MyClass<U>
, where U
is the generic type parameter.
I am trying to write a utility method which accepts a class reference Class<T>
and populates a map of type Map<String, T>
(accepts the map to populate).
This method is implemented like:
static void populateMap(Map<String, T> map, Class<T> type) {
...
// Parses into the specified type and returns an object of that type.
T obj = parse(..., type);
map.put (key, obj);
...
return map;
}
This compiles fine. In my caller, I attempt to populate a map with any MyClass
instance (irrespective of type) as the value. Hence I use the following code:
// Loses type information
Map<String, MyClass<?>> m = new HashMap<>();
populateMap(m, MyClass.class);
This does not compile. Compilation error:
The method
populate(Map<String,T>, Class<T>)
in the type ... is not applicable for the arguments(Map<String,MyClass<?>>, Class<MyClass>)
How can I fix this?
Because of type erasure, there's no such thing as a Class object representing a generic type, you can only use a raw type such as MyClass (with no generic parameter).
One possible workaround is exceptionally ugly: declare or cast m as
Map<String, MyClass>
and prepare to face a tsunami of warnings and errors (errors can be fixed by casting, and become multiple warnings).For a probably better workaround, refer to Paul's answer :)
Also see Getting a java.lang.Class with generics
In this case it should be safe to do an unchecked cast to
Class<MyClass<?>>
:This is a crufty solution, especially if you have many call sites like this, but there's no getting around the fact that class literals are parameterized with raw types, making their use as factories of parameterized types like
MyClass<T>
inherently awkward.A potentially cleaner solution would decouple
populateMap
from the use of class literals:As an aside I recommend a more flexible signature (see What is PECS (Producer Extends Consumer Super)? for more info):