Подтвердить что ты не робот

Проблема с ошибкой Джерси/Джексона с 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, поэтому у меня нет возможности его сопоставить?

Есть ли у кого-нибудь идеи? Большое спасибо и извините за мой английский;)

4b9b3361

Ответ 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, чтобы вернуть свое пользовательское содержимое ответа. Я не доволен этим, но теперь он работает!

Спасибо за вашу помощь!