Details
-
Bug
-
Status: Closed
-
Minor
-
Resolution: Fixed
-
3.4.2
-
None
-
Unknown
Description
MP Async methods have a return type of CompletionStage<?> and the exception processing should occur via the CS, not on the actual invocation of the method. So if a response exception mapper is registered with a MP Rest Client interface, the associated exception should be on the throws clause for synchronous methods, but not necessarily for asynchronous methods.
Here's and example:
public interface MyClient { @GET @Path("sync") String getSync() throws MyCustomException; @GET @Path("async") CompletionStage<String> getAync();
public class MyCustomExceptionResponseMapper implements ResponseExceptionMapper<MyCustomException> { @Override public boolean handles(int status, MultivaluedMap<String, Object> headers) { return status == 499; } @Override public MyCustomException toThrowable(Response response) { return new MyCustomException(); } }
For sync invocation, we would expect the invocation to throw the exception:
try { myClient.getSync(); } catch (MyCustomException ex) { //... }
But for async invocation, we would expect the exception to be throw from the CompletionStage<?>, like:
CompletionStage<String> cs = myClient.getAsync(); cs.exceptionally(ex -> { Throwable cause = ex.getCause(); // ex should be a CompletionException if (cause instanceof MyCustomException) { // ... } }); // or try { cs.toCompletableFuture().get(); } catch (ExecutionException ex) { Throwable cause = ex.getCause(); if (cause instanceof MyCustomException) { //... } }
Currently, the async flow fails because CXF is checking that the exception type is listed in the throws clause of the interface method signature. So instead of throwing a MyCustomException wrapped in a CompletionException (or ExecutionException), it is throwing a wrapped WebApplicationException.