I'm trying to make a "registry" of handlers that return a specific type
public class HandlerRegistry {
Map<Class<?>, Handler<?>> handlers;
<T> void setHandler(Class<T> type, Handler<? extends T> handler) {
handlers.put(type, handler);
}
<T> T handle(Class<T> type, HandlerArgument arg) {
Handler<? extends T> handler = getHandler(type);
return handler.handle(arg);
}
<T> Handler<? extends T> getHandler(Class<T> type) {
// warning produced here "uses unchecked or unsafe operations."
return (Handler<? extends T>)handlers.get(type);
}
}
I know that this particular cast will never fail at runtime, but other than using @SuppressWarnings("unchecked")
is there a way to tell the compiler that this is indeed safe?
I'm using Java 8 specifically, if there is a more elegant way to do what I want in 8.
Generally, an unchecked operation is unavoidable in this case. The best thing you can do is to isolate the unchecked operation and guard it with a safe test. One proven solution is to wrap the instance in a holder instance which encapsulates the unchecked operation and enforces the pre-check:
class HandlerRegistry {
private static class Holder<T> {
private final Class<T> type;
private final Handler<? extends T> handler;
Holder(Class<T> c, Handler<? extends T> h) {
type=Objects.requireNonNull(c);
handler=h;
}
<U> Holder<U> as(Class<U> expected) {
if(type!=expected)
throw new ClassCastException();
@SuppressWarnings("unchecked") Holder<U> h=(Holder)this;
return h;
}
public Handler<? extends T> getHandler() {
return handler;
}
}
Map<Class<?>, Holder<?>> handlers;
<T> void setHandler(Class<T> type, Handler<? extends T> handler) {
handlers.put(type, new Holder<>(type, handler));
}
<T> T handle(Class<T> type, HandlerArgument arg) {
return getHandler(type).handle(arg);
}
<T> Handler<? extends T> getHandler(Class<T> type) {
return handlers.get(type).as(type).getHandler();
}
}
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