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