Skip to content

Resteasy reactive client does not create specific WebApplicationException #23951

Open
@chonton

Description

Describe the bug

When a rest api returns a 4xx or 5xx status code, Resteasy reactive client creates a generic WebApplicationException

I must register the following ResponseExceptionMapper<RuntimeException> to get the expected behavior. Please consider adding this code to org.jboss.resteasy.microprofile.client.DefaultResponseExceptionMapper:

package com.example.client.jaxrs;

import java.util.function.Function;
import javax.inject.Singleton;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotAcceptableException;
import javax.ws.rs.NotAllowedException;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.NotSupportedException;
import javax.ws.rs.RedirectionException;
import javax.ws.rs.ServerErrorException;
import javax.ws.rs.ServiceUnavailableException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;

@Singleton
public class ClientExceptionMapper implements ResponseExceptionMapper<RuntimeException> {

  private static Function<Response, ServerErrorException> serverExceptionConstructor(int status) {
    switch (status) {
      case 500:
        return InternalServerErrorException::new;
      case 503:
        return ServiceUnavailableException::new;
      default:
        return ServerErrorException::new;
    }
  }

  private static Function<Response, ClientErrorException> clientExceptionConstructor(int status) {
    switch (status) {
      case 400:
        return BadRequestException::new;
      case 401:
        return NotAuthorizedException::new;
      case 403:
        return ForbiddenException::new;
      case 404:
        return NotFoundException::new;
      case 405:
        return NotAllowedException::new;
      case 406:
        return NotAcceptableException::new;
      case 415:
        return NotSupportedException::new;
      default:
        return ClientErrorException::new;
    }
  }

  private static Function<Response, ? extends WebApplicationException> webApplicationException(
      int status) {

    if (status < 600) {
      if (status >= 500) {
        return serverExceptionConstructor(status);
      }
      if (status >= 400) {
        return clientExceptionConstructor(status);
      }
      if (status >= 300) {
        return RedirectionException::new;
      }
    }
    return WebApplicationException::new;
  }

  @Override
  public RuntimeException toThrowable(Response response) {
    int status = response.getStatus();
    if (status < 100 || status >= 300) {
      return webApplicationException(status).apply(response);
    }
    return null;
  }
}

Expected behavior

Produce a specific WebApplicationException such as ForbiddenException for 403 or NotFoundException for 404. This is the behavior of classic Resteasy client.

Actual behavior

Resteasy reactive client creates a generic WebApplicationException with the correct status code.

How to Reproduce?

Invoke any web service that returns a 4xx or 5xx status code

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions