Here's a simple example that demonstrates a type-erasure-related issue I am running into. I have a class like this:
public abstract class AbstractHandler<T> {
...
public abstract Class<T> handledType();
}
Then I have this implementation:
public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {
@Override
public Class<Map<String, List<Thing>>> handledType() {
//what do I return here?!
}
}
I can't return Map<String, List<Thing>>.class
, since that's not even valid syntactically. I tried making the generic type-parameter in the subtype to be HashMap<String, List<Thing>>
and then returning new HashMap<String, List<Thing>>().getClass()
, but that doesn't work because the return type of Class<T>#getClass()
is Class<? extends T>
. I looked at TypeToken
from Guava, and the getRawType
method seemed promising, but it returns Class<? super T>
.
I have a workaround for the time being that looks like this:
public class ThingListMap {
private Map<String, List<Thing>> thingListMap;
...
}
and I just use ThingListMap
as the generic type-parameter.
Another possible workaround is to perform a forced cast:
public Class<Map<String, List<Thing>>> handledType() {
return (Class<Map<String, List<Thing>>>) new HashMap<String, List<Thing>>().getClass();
}
Is there a more-elegant way to do this?
EDIT: In response to one of the answers, I cannot change the signature of the handledType
method since I do not own or control its source.
For some reason, Java doesn't allow you to cast Map.class
directly to Class<Map<String, List<Thing>>>
. It's an unchecked cast anyway.
But it's legal to cast it twice, first to Class<?>
, then to Class<Map<String, List<Thing>>>
.
return (Class<Map<String, List<Thing>>>) (Class<?>) Map.class;
Being an unchecked cast, you may want to add @SuppressWarnings("unchecked")
.
Guava's approach to this is to use TypeToken
s. Your class would become
public abstract class AbstractHandler<T> {
public TypeToken<T> handledType();
}
public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {
@Override
public TypeToken<Map<String, List<Thing>>> handledType() {
return new TypeToken<Map<String, List<Thing>>>() {};
}
}
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