Как переопределить встроенный картограф исключения в Джерси 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);