Это ожидаемое поведение, основанное на Разделе 3.3.4 (и 4.5.1) JAX-RS 2.0 Spec .В этих разделах описывается, как обрабатываются исключения из ресурсов и поставщиков JAX-RS - вкратце:
- Если исключение составляет
WebApplicationException
, то оно автоматически сопоставляется с Response
. - Если есть зарегистрированный
ExceptionMapper
, который может обработать выброшенное исключение, то это будет использоваться для генерации ответа. - Непроверенные исключения передаются в контейнер (т. Е. Код реализации JAX-RS Liberty).
- Несопоставленные исключения должны обрабатываться через специфичное для контейнера исключение, а затем соответствующим образом распространяться в нижележащий контейнер - в этом случае
ServletException
необходимо передать в веб-контейнер.
JaxRsRuntimeException
используется для выполнения шага 4.
В этом сценарии встроенный поставщик JSON (на основе Jackson 1.X) выбрасывает EOFException
.Поскольку для исключения EOFException (или любого из его суперклассов) нет сопоставителей исключений, в конечном итоге оно сопоставляется с ServletException
посредством JaxRsRuntimeException
.
Для того чтобы приложение могло обрабатывать этот сценарий, есть несколько различных опций:
- Вы можете зарегистрировать
ExceptionMapper
, специфичный для этого типа исключения (EOFException
или любой из его суперклассов - т.е. IOException
).Вам не нужно регистрировать маппер для JaxRsRuntimeException
, поскольку это исключение используется только в Liberty для внутренних целей и не должно отображаться.Если вы видите, что JaxRsRuntimeException передается в ExceptionMapper
, то вам следует открыть службу поддержки в IBM, поскольку это, скорее всего, ошибка.
С ExceptionMapper<EOFException>
вы можете вернуть определенный ответвсякий раз, когда EOFException
выбрасывается из провайдера или ресурса.
Вы можете зарегистрировать свой собственный
MessageBodyReader
, который будет преобразовывать JSON в объекты (используя Джексона или любой другой код сериализации JSON), но который будет обрабатывать пустые тела сообщений так, как вы хотите - например, преобразовать его в
null
илииспользуя какой-то экземпляр объекта по умолчанию.Поскольку зарегистрированные пользователем поставщики имеют приоритет перед встроенными поставщиками, этот MBR будет использоваться вместо MBR Liberty на основе Джексона.
Такой подход определенно дает вам больший контроль над тем, как десериализуются данные.как обработка исключений.
Зарегистрируйте ContainerRequestFilter
провайдера, который прервет работу, когда тело сообщения будет пустым.Вот пример:
@Provider
public class EmptyBodyCheckFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext crc) throws IOException {
if (crc.getEntityStream().available() < 1) {
crc.abortWith(Response.status(400).entity("Invalid request - empty message body").build());
}
}
}
Я успешно протестировал варианты 1 и 3 с использованием WebSphere Liberty, май 2018 Beta.Я лично не тестировал вариант 2 для этого сценария, но на основе использования пользовательских MBR в прошлом это должно работать.
Следует иметь в виду, что когда Liberty GA имеет функцию jaxrs-2.1
, онабудет использовать JSONB в качестве встроенного поставщика для сериализации / десериализации JSON вместо Джексона.Я протестировал ваш сценарий, используя JAX-RS 2.1 (также в бета-версии мая), и вместо EOFException
код JSONB выдает NoSuchElementException
.Если вы считаете, что можете перейти на JAX-RS 2.1, я бы предложил вариант 2 или 3. Для варианта 1 потребуется создать новый ExceptionMapper
для JAX-RS 2.1.
Надеюсь, это поможет,
Энди