Simplest is to pass the parser as an argument to the constructor:
public abstract class ProtoDeserializer<T extends Message> {
private final Parser<T> parser;
public ProtoDeserializer(Parser<T> parser) {
this.parser = parser;
}
public T deserialize(final byte[] bytes) throws Exception {
T message = parser.parseFrom(bytes);
validate(message);
return message;
}
public abstract void validate(final T message) throws Exception;
}
Passing the parser is my current workaround. But it would be nice to avoid it, because it's redundant information.
It may be redundant to you, but it is not redundant to the compiler/runtime.
If you consider that it is possible to create raw implementation of your class:
ProtoDeserializer proto = new ProtoDeserializer() {
...
};
The type T
would have to come from somewhere.
This is just the reality of erased generics. If you need type information of a generic parameter, you will have to manually supply it.
Another hack you can try is to get the concrete type parameter from an implementing sub class:
private final Parser<T> parser;
public ProtoDeserializer() {
Class<?> subclass = this.getClass();
try {
ParameterizedType pType = (ParameterizedType) subclass.getGenericSuperclass();
Class<T> tClass = (Class<T>) pType.getActualTypeArguments()[0];
// In the case where the constructor for `T` takes no arguments.
parser = tClass.newInstance().getParserForType();
} catch(Throwable t) {
throw new RuntimeException("Subclass not compatible", t);
}
}
This would work as long as the subclass directly implements ProtoDeserializer
with a concrete type argument. i.e.:
class MyDeserializer extends ProtoDeserializer<MyMessage> {...}