Проблема с ошибкой Джерси/Джексона с ExceptionMapper
Я использую Джерси, чтобы предоставить услугу REST Java для внешнего мира. Я предлагаю некоторые функции, которые принимают JSON, и я использую структуру Jackson в сочетании с трикотажем, чтобы преобразовать их в POJO.
У меня возникла проблема, что если на сервер отправляется неправильный формат джексона, ответ (содержимое ответа HTTP) является описанием исключения для джексона. Если у меня есть POJO с атрибутом "фамилия" и отправьте "sursname" в строке json на сервер, я получаю:
Unrecognized field "sursname" (Class XY), not marked as ignorable at [Source: [email protected]; line: 1, column: 49] (through reference chain: XY["sursname"])
Это нормально, но я хотел бы иметь собственный контент для ответа, например, свой собственный код ошибки. Я уже написал пользовательский ExceptionMapper, который должен отображать все Throwables.
@Provider
public class WebserviceExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Exception e) {
e.printStackTrace();
return Response.status(400).entity("{\"errorcode\":\"CRITICAL_ERROR\"}").type(MediaType.APPLICATION_JSON).build();
}
}
Кажется, что исключение Jackson выбрано перед вызовом метода webservice, поэтому у меня нет возможности его сопоставить?
Есть ли у кого-нибудь идеи? Большое спасибо и извините за мой английский;)
Ответы
Ответ 1
Причина, по которой ваш пользовательский ExceptionMapper не улавливает исключения, заключается в том, что библиотека Jackson предоставляет свои собственные механизмы-исключения, которые улавливают исключение, прежде чем оно будет уловлено вашим генетическим редактором исключений.
Некоторые предполагают, что вы должны реализовать свои собственные механизмы-исключения для JsonParseExceptionMapper и JacksonMappingExceptionMapper, но это, однако, даст непоследовательные результаты. Посмотрите эту проблему на своем GitHub.
Чтобы решить эту проблему, вы должны убедиться, что ни один из встроенных преобразователей исключений не зарегистрирован. Если вы используете библиотеку jackson-jaxrs-providers для JSON: jackson-jaxrs-json-provider, убедитесь, что вы регистрируете только JacksonJaxbJsonProvider. class или JacksonJsonProvider.class в вашем классе Application:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(JacksonJaxbJsonProvider.class)
}
}
Помните о JacksonFeature.class, поскольку он регистрирует встроенные ExceptionMappers. Также держитесь подальше от библиотеки jersey-media-json-jackson, которая автоматически добавит некоторые встроенные средства отображения исключений, без необходимости делать что-либо вообще.
Ответ 2
Я столкнулся с подобной проблемой некоторое время назад при использовании Jackson и Apache CXF. Экземпляры исключений не вызывались, если исключение не произошло в моем методе JAX-RS и вместо этого произошло в JacksonJsonProvider
. Решение в моем случае состояло в том, чтобы расширить JacksonJsonProvider
, уловить конкретные исключения Джексона json и перебросить их как WebApplicationException
.
Здесь мой расширенный метод readFrom для моего расширенного JacksonJsonProvider
:
@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
try {
return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream);
} catch (JsonParseException jpe) {
throw new WebApplicationException(jpe, Response.status(Status.BAD_REQUEST)
.entity(new ErrorEntity("Malformed json passed to server: \n" + jpe.getMessage())).build());
} catch (JsonMappingException jme) {
throw new WebApplicationException(jme, Response
.status(Status.BAD_REQUEST)
.entity(new ErrorEntity("Malformed json passed to server, incorrect data type used: \n"
+ jme.getMessage())).build());
}
}
Ответ 3
Конечно, исключение Jackson выбрано раньше: поставщик Jackson вызывается для создания объекта, который вы ожидаете в своем методе. Однако с помощью ExceptionMapper вы должны иметь возможность отображать не только ваши исключения, но и исключение провайдеров.
Вы уверены, что ваш провайдер зарегистрирован? Вызывается ли это, если вы выбрали исключение из своего метода, а не провайдера?
Если ответ на предыдущий вопрос "да", попробуйте реализовать ExceptionMapper для конкретного исключения вместо Throwable.
Ответ 4
У меня была та же проблема и решалось переопределить ExceptionMapper. Отлично! Еще одна вещь, которую мне нужно было сделать и которая не понимала 100%, заключалась в том, как переопределить JacksonProvider для моего приложения (я не знаю, было ли это связано с версией Джерси, которую я использовал - 2.19). Здесь моя часть web.xml, которая ее переопределяет:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider
</param-value>
Ответ 5
Спасибо за вашу помощь, ExceptionMapper для JsonParseException не помогло. Я удалил файлы json json из моего проекта и включил источники Джексона. Затем я изменил ord.codehaus.jackson.jaxrs.JsonParseExceptionMapper и JacksonMappingExceptionMapper, чтобы вернуть свое пользовательское содержимое ответа. Я не доволен этим, но теперь он работает!
Спасибо за вашу помощь!