Osman-pasha
Osman-pasha

Reputation: 632

How to tell java that a generic type is a functional interface?

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

Answers (1)

Holger
Holger

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

Related Questions