I think my fix maybe more of a workaround. I was just disgnosing a bit more. The problem I was having was the UniInvokerProvider was returning a wrapped CompletionStageRxInvokerImpl instead of an AsyncInterceptorRxInvoker. The AsyncIntercerptorRxInvoker from resteasy-client-microprofile adds a finally to the CompletionStage that runs the exception mappers on the async exceptions that created with org.jboss.resteasy.microprofile.clienf.ExceptionMapping. this leaves a HandlerException "Handled Internally" to be returned instead of WebApplicationException.
CompletionStage works fine. My workaround was to register my own version of UniInvokerProvider that explicitly wraps a new AsyncInterceptorRxInvoker. This is not a solution in the main code as UniInvokerProvider does not have resteasy-client-microprofile as a dependency. I am not sure whether we should have a different subclass of ClientInvocationBuilder passed in as it is this that is specifically creating a new instance of CompletionStageRxInvokerImpl in the rx() method instead of the AsyncInterceptorRxInvoker that is needed.
Below is the workaround.
The issue I had with uploading file was it was failing to find the MessageBodyReader when I used an Uni in my return type and was sending a MultiPartForm. The problem is that the entity object is getting recreated in the flow of using the Uni and the the annotations list is not being passed in the argument list, this is an issue with CompletionStage also and not specific to Quarkus. How do we usually handle this kind of bug in quarkus the fix is in resteasy-client org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker
@POST
@Path("feeds")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
Uni<FeedAcknowledgement> postFeeds(
@QueryParam("feedType") FeedType feedType,
@QueryParam("setupType") String setupType,
@MultipartForm MultipartBody body);
Workaround for exception handling issue
import io.quarkus.resteasy.mutiny.common.runtime.UniRxInvoker;
import io.quarkus.resteasy.mutiny.common.runtime.UniRxInvokerImpl;
import java.util.concurrent.ExecutorService;
import javax.annotation.Priority;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.RxInvokerProvider;
import javax.ws.rs.client.SyncInvoker;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;
import org.jboss.resteasy.microprofile.client.async.AsyncInterceptorRxInvoker;
@Provider
@Priority(1)
public class FixupUniInvokerProvider implements RxInvokerProvider<UniRxInvoker> {
@Override
public boolean isProviderFor(Class<?> clazz) {
return UniRxInvoker.class.equals(clazz);
}
@Override
public UniRxInvoker getRxInvoker(SyncInvoker syncInvoker, ExecutorService executorService) {
if (syncInvoker instanceof ClientInvocationBuilder) {
return new UniRxInvokerImpl(new AsyncInterceptorRxInvoker(syncInvoker, executorService));
} else {
throw new ProcessingException("Expected a ClientInvocationBuilder");
}
}
}