Как переопределить встроенный картограф исключения в Джерси 2.23?

В одном из моих проектов я уже обновил Джерси с версии 2.14 в 2.23, Но я много часов бьюсь над одной проблемой. Мой проект определяет свой собственный ExceptionMapper для ValidationException, но, к сожалению, в Джерси уже есть встроенный сопоставитель исключений для этого исключения, и я не могу его переопределить.

Я правильно зарегистрировал (я проверил это) мой собственный картограф, который представлен ниже:

@Provider
public class ValidationExceptionMapper implements 
         ExceptionMapper<ValidationException> {

    @Override
    public Response toResponse(ValidationException exception) {
        return Response.status(Status.BAD_REQUEST).build();
    }
}

но это никогда не называется. Джерси всегда подбирать org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper, Я также пытался использовать @Priority аннотация для моего пользовательского картографа, но, к сожалению, Джерси не принимает это во внимание.

Так, что происходит? Он отлично работал в предыдущей версии Джерси, так что, похоже, это ошибка регрессии.

Я сдаюсь. Есть какие-нибудь подсказки?

4 ответа

Решение

Это действительно оказалось ошибкой регрессии в Джерси, появившейся в январе 2015 года.

Ошибка связана с двумя расширениями Джерси: для валидации и проверки бобов. Потому что без сварки начался контейнер, мой кастом ValidationExceptionMapper картостроитель имеет приоритет над встроенным, предоставленным jersey-bean-validation модуль, поэтому моя цель достигнута.

Я заполнил отчет об ошибке под JERSEY-3153.

Если честно, я никогда больше не буду использовать Weld + Jersey... Я так устал от этой комбинации. За последние два года я уже столкнулся с 10 ошибками. Я действительно устал.

Во всяком случае, я надеюсь, что это кому-нибудь поможет.

ОБНОВЛЕНИЕ: Как заметил @Justin Jose в комментариях ниже, есть еще один обходной путь для упомянутой ошибки. Мы можем использовать привязки HK2, чтобы переопределить проблемный встроенный преобразователь:

register(new AbstractBinder() {
    @Override
    protected void configure() {
        bind(my.custom.ValidationExceptionMapper.class).to(ExceptionMapper.class)
               .in(Singleton.class);
    }
});

Встроенный в Джерси ValidationExceptionMapper зарегистрирован через ValidationFeature. Возможно, замена Jerid's ValidationFeature собственной версией может помочь. Это можно сделать следующим образом.

Во-первых, отключите автоматически обнаруживаемую ValidationFeature

property(ServerProperties.BV_FEATURE_DISABLE, true);

Следующим шагом является регистрация клона функции проверки Джерси.

public static class ValidationFeatureClone implements Feature {

    @Override
    public boolean configure(FeatureContext context) {
        context.register(new ValidationBinder());
        context.register(NewValidationExceptionMapper.class);
        context.register(ValidationErrorMessageBodyWriter.class);
        return true;
    }
}

В клоне вы должны указать свой новый ExceptionMapper.

Наконец, зарегистрируйте вашу новую функцию

register(ValidationFeatureClone.class)

ОБНОВИТЬ:

С Джерси 2.20 и далее по умолчанию ValidationExceptionMapper может быть перезаписан с использованием привязки HK2, как показано ниже.

register(new AbstractBinder() {
    @Override
    protected void configure() {

       bind(NewValidationExceptionMapper.class).to(ExceptionMapper.class)
           .in(Singleton.class).ranked(10‌​);
    }
});

Я нашел способ заставить его работать с более новыми выпусками Джерси, который я также разместил в вашем отчете об ошибках.

Нужно построить Джерси локально с измененным кодом, особенно jersey-bean-validation артефакт.

разместить org.glassfish.jersey.server.validation.internal.ValidationBinder и закомментируйте следующие две строки в configure():

bind(ValidationExceptionMapper.class).to(ExceptionMapper.class).in(Singleton.class);
bind(ValidationErrorMessageBodyWriter.class).to(MessageBodyWriter.class).in(Singleton.class);

Ирония в том, что комментарий к исходному тексту над этими строками говорит о том, что они должны позволять пользователям регистрировать своих собственных провайдеров.

К сожалению, ошибка все еще существует и вызывает головную боль... В моем случае самым простым решением было предоставление пользовательского ExceptionMapper специально для ConstraintViolationException.

      public class CVExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
   @Override
   public Response toResponse(final Throwable t) {
   ...
   }
}

а затем зарегистрировать его, как всегда, с помощью:context.register(CVExceptionMapper.class);

Другие вопросы по тегам