I am fully aware this question was asked many times, but I cannot find an answer to it. :/
I have one parametrized class:
public class MessageType<T> {
private final Class<T> clazz;
public MessageType(final Class<T> clazz) {
this.clazz = clazz;
}
public Class<T> getClazz() {
return clazz;
}
}
And several static objects of this class:
static final MessageType<String> TYPE_A = new MessageType<>(String.class);
static final MessageType<Double> TYPE_B = new MessageType<>(Double.class);
static final MessageType<List<String>> PROBLEM_TYPE = new MessageType(List.class);
The problem is that I have to omit diamond operator and stick to unchecked cast of MessageType
to MessageType<List<String>>
in the last line.
I would like to write something like
static final MessageType<List<String>> PROBLEM_TYPE = new MessageType<>(List<String>.class);
but List<String>.class
cannot be computed in runtime as, you know, type erasure. :D
➥ Is there any way to comply with the compiler, and avoid unchecked casts? (It has already costed me an hour due to my negligence and lack of attention)
You can't avoid the unchecked cast here; List<String>
is not a Class<?>
but a ParameterizedType
(both extend/implement Type
but have no further common parent). You can store and use the type information of List<String>
(with an ParameterizedType
). But there will always be some unchecked cast to get back to List<String>
.
There are some options for workarounds. Most are tailored to the actual usecase.
You can move the unchecked cast into MessageType:
public <T> static MessageType<List<T>> createListMessage(Class<T> innerType){
return (MessageType<List<T>>) (Object) new MessageType(List.class);
}
If you need Class to create a new Instance. Provide a Supplier<T>
.
private final Supplier<T> supplier;
public MessageType(Supplier<T> supplier){
this.supplier = supplier;
}
public T newType(){
return supplier.get();
}
MessageType<String> STRINGS = new MessageType(String::new);
MessageType<List<String>> STRING_LIST = new MessageType(ArrayList::new);
If you need it for serialization a Supertype-Token is an option.