Reputation: 632
I have a generic functional interface to ask user about errors (pretty same as java.util.function.Function) and some parametrized subinterfaces:
@FunctionalInterface
public interface Handler<Err,Resp> {
public Resp handle(Err param);
}
@FunctionalInterface
public interface RecoverableErrorHandler<Err> extends Handler<Err, RecoverableErrorResult > {}
@FunctionalInterface
public interface RetryIgnoreErrorHandler<Err> extends Handler<Err, RetryIgnoreAbortResult> {}
I want to add logging to each handler by wrapping handler into another handler:
private <Err,Resp,H1 extends Handler<Err,Resp> > H1 addLogToHandler(String s, H1 h) {
return (Err arg) -> {
Resp res = h.handle(arg);
logger.info(s+" returned "+res);
return res;
};
}
// some code omitted
RecoverableErrorHandler<String> netErrorHandler = ... // shows dialog and asks user what to do
netErrorHandler = addLogToHandler("Network Error handler", netErrorHandler);
This does not compile with error: incompatible types: H1 is not a functional interface
on line with return
.
The question is, can I tell java that generic H1
is a functional interface? Or, how do I make this code work?
Upvotes: 3
Views: 714
Reputation: 298153
There is no way to tell the compiler that H1
is supposed to be a functional interface, in fact, you can’t even tell it that H1
is supposed to be an interface.
When you think about it, you may notice that even if you were able to restrict H1
to be a functional interface extending Handler<Err,Resp>
, there was no guaranty that this type has a functional type compatible to the lambda expression in your code.
E.g., the following would be a type fulfilling the constraints:
@FunctionalInterface
public interface Foo<E,R> extends Handler<E,R>, Runnable {
default R handle(E param) { run(); return null; }
}
this is a functional interface and it extends Handler
, but the attempt to implement it within addLogToHandler
with a (Err) -> Resp
signature can’t work.
The solution is simple. Just drop the sub interfaces RecoverableErrorHandler<Err>
and RetryIgnoreErrorHandler<Err>
completely. They offer no advantage over using Handler<Err,RecoverableErrorResult>
resp. Handler<Err,RetryIgnoreAbortResult>
directly.
After eliminating the subtypes, you can change the method to
private <Err,Resp> Handler<Err,Resp> addLogToHandler(String s, Handler<Err,Resp> h) {
return arg -> {
Resp res = h.handle(arg);
logger.info(s+" returned "+res);
return res;
};
}
Upvotes: 3