Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-8427

Response exception mappers not invoked on MP async methods

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 3.4.2
    • Fix Version/s: 3.5.0, 3.4.3
    • Component/s: MicroProfile
    • Labels:
      None
    • Estimated Complexity:
      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.

        Attachments

          Activity

            People

            • Assignee:
              amccright Andy McCright
              Reporter:
              amccright Andy McCright
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: