Статьи

Конфигурируемый JAX-RS ExceptionMapper с конфигурацией MicroProfile

Когда вы создаете сервисы REST с JAX-RS, вы обычно либо ничего не возвращаете (например, HTTP 201/2/4 и т. Д.), Либо некоторые данные, возможно в формате JSON (например, HTTP 200), или некоторые исключения / ошибки (например, HTTP 4xx или 5xx). ).

Обычно мы переводим исключение времени выполнения в какой-то HTTP 5xx, а проверенное исключение — в 4xx.

Поскольку мы хотим сохранить нашу границу чистой, мы не включаем полную трассировку стека Java в тело ответа, когда переводим исключение в ответ HTTP. Обычно мы просто добавляем заголовок «REASON» с ответом HTTP 5xx (или иногда 4xx). Однако это означает, что большинство наших ExceptionMappers выглядит примерно одинаково (примерно так):

1
2
3
4
5
6
7
8
9
@Provider
    public class SomeExceptionMapper implements ExceptionMapper<SomeException> {
 
        @Override
        public Response toResponse(SomeException exception) {
            return Response.status(500).header("reason", exception.getMessage()).build();
        }
 
    }

Использование MicroProfile Config API

Мы можем использовать MicroProfile Config API для создания настраиваемого сопоставления исключений, которое позволяет потребителю настраивать сопоставление кода ответа исключения и HTTP.

Наш @Provider будет обрабатывать все исключения времени выполнения:

1
2
3
4
@Provider
    public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
        // ...
    }

Мы @Inject и Config и провайдеров:

1
2
3
4
5
@Inject
    private Config config;
     
    @Context
    private Providers providers;

Когда мы реализуем метод toResponse , мы видим, есть ли отображение для этого класса Exception в нашей конфигурации:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
    @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
    public Response toResponse(RuntimeException exception) {
        return handleThrowable(exception);
    }
     
    private Response handleThrowable(Throwable exception) {
        if(exception instanceof WebApplicationException) {
            return ((WebApplicationException) exception).getResponse();
        }
        if(exception!=null){
            String configkey = exception.getClass().getName() + STATUS_CODE_KEY;
            Optional<Integer> possibleDynamicMapperValue = config.getOptionalValue(configkey,Integer.class);
            if(possibleDynamicMapperValue.isPresent()){
                int status = possibleDynamicMapperValue.get();
                // You switched it off
                if(status<0)return handleNotMapped(exception);
                String reason = getReason(exception);
                log.log(Level.FINEST, reason, exception);
                return Response.status(status).header(REASON, reason).build();
            } else if(exception.getCause()!=null && exception.getCause()!=null && providers!=null){
                final Throwable cause = exception.getCause();
                return handleThrowable(cause);
            } else {
                return handleNotMapped(exception);
            }
        }
        return handleNullException();
    }

(полный пример здесь )

Мы также поднимаемся по цепочке исключений до тех пор, пока не получим сопоставление, или затем по умолчанию устанавливаем нормальную ошибку 500

Таким образом, мы можем добавить конфигурацию для сопоставлений следующим образом:

1
2
3
4
5
## 503 Service Unavailable: The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state.
    org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException/mp-jaxrs-ext/statuscode=503
     
    ## 401 Unauthorized (RFC 7235): Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided.
    javax.ws.rs.NotAuthorizedException/mp-jaxrs-ext/statuscode=401

В приведенном выше примере мы отобразим исключение CircuitBreakerOpenException (из API отказоустойчивости MicroProfile) в 503, а NotAuthorizedException — в 401.

Пример скриншота

ExceptionMapper

Используйте это как библиотеку.

Вы также можете объединить все это в jar-файл, который будет использоваться любым вашим проектом. Я сделал вышеперечисленное доступным в Maven Central и GitHub , так что вы также можете использовать это напрямую.

Просто добавьте это в ваш pom.xml

1
2
3
4
5
<dependency>
        <groupId>com.github.phillip-kruger.microprofile-extensions</groupId>
        <artifactId>jaxrs-ext</artifactId>
        <version>1.0.9</version>
    </dependency>

Он поставляется с несколькими предопределенными сопоставлениями, но вы можете переопределить его в своей конфигурации.

Опубликовано на Java Code Geeks с разрешения Филиппа Крюгера, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Настраиваемый JAX-RS ExceptionMapper с MicroProfile Config

Мнения, высказанные участниками Java Code Geeks, являются их собственными.