1

I've been trying to understand how to properly handle exceptions when using CompletionStage, I've looked at the exceptionally() method but that is not good enough for my needs, I don't want to use it to intercept an exception thrown by an async method and pass along a new default value, I want it to intercept an exception, possibly break the chain and replace the current class of the output element of the chain with another one, in particular the output class of the main method.

This is a sample code:

public CompletionStage<Result> getTableAsJSON(String instance, Http.Request request) {
        return this.repositoryManager.getRepository(instance).map(repo ->
            repo.getTabularData(request.queryString()).exceptionally(ex -> {
                return new ArrayList<>();
            }).thenApplyAsync(list -> {
                    if(!list.isEmpty())
                        return ok(toJson(list));
                    else
                        return notFound(this.messagesApi.preferred(request).at("noDataFound"));
                }, this.httpExecutionContext.current()
            )        ).orElse(CompletableFuture.completedFuture(notFound(this.messagesApi.preferred(request).at("instanceNotFound"))));
    }

In the code above, if a SqlException is thrown inside getTabularData, exceptionally catches it and passes along an empty list because getTabularData's signature is

CompletionStage<List<?>> getTabularData(Map<String, String[]> parameters);

It's true that inside exceptionally I could differentiate between a SqlException or a NumberFormatException, but in the end it must pass along a List to the thenApplyAsync, and once the flow gets in there, it can't differenciate between what exception was raised and return a different Result accordingly.

Is there a better way than using the old school try catch blocks to accomplish proper exception handling with CompletionStage?

Thank you, Roberto

Roberto
  • 15
  • 2
  • 2
    Just don’t substitute the exception with an empty `ArrayList`. We can’t tell you what to do instead, since you didn’t say how you want to handle the exceptions. If you want the caller of `getTableAsJSON` to handle exceptional cases, just remove the `.exceptionally(ex -> { return new ArrayList<>(); })` without any replacement. – Holger Jun 11 '20 at 08:02
  • Basically I need to do something like this: public CompletionStage ... { return this.repositoryManager.getRepository(instance).map(repo -> repo.getTabularData(request.queryString()).exceptionally(ex -> { return an instance or Result (say an internal server error result) }).thenApplyAsync(list -> { if(!list.isEmpty()) return ok; else return notFound error; }, this.httpExecutionContext.current() ) ) } – Roberto Jun 11 '20 at 09:22
  • 2
    Just use `repo.getTabularData(…) .thenApplyAsync(list -> /* process list */) .exceptionally(ex -> /* return error result */)` – Holger Jun 11 '20 at 09:45
  • I suppose that in this example I could simply swap the order of thenApply and exceptionally because there is just one link in the chain anyways, but if I have say a more complex chain of thenCompose and thenApply, putting exceptionally in the end is possibly not enough. Say that a link in the middle of the chain throws an exeption, I can definitely imagine the scenario in which I wanna check what expcetion that is and either break the chain and return a Result right away, or handle the exception and forward a default value to the following thenApply. I guess it can't be done – Roberto Jun 11 '20 at 12:43
  • 2
    I don’t see the problem. You can insert an `exceptionally` wherever mapping to a reasonable default value is possible. Otherwise, chain `exceptionally` at the end. There is no need to “break the chain”, when an exception occurs, all subsequent stages are skipped anyway (how could it work otherwise when no input for these stages exist?). The only stages that are not skipped in the exceptional case are `handle[Async]`, `whenComplete[Async]`, and `exceptionally​`. – Holger Jun 11 '20 at 13:00
  • I see what you mean, thank you for your clarification Holger – Roberto Jun 12 '20 at 06:49

0 Answers0