В моем проекте используется Spring Boot + Jersey 2.
Я создал пользовательский сопоставитель Jackson для JsonParseException, но он не получил вызов, вместо этого использовался стандартный Jackson JsonParseExceptionMapper.
Мой пользовательский сопоставитель:
package com.rmn.gfc.common.providers;
import ...
@Provider
public class JsonParseExceptionHandler implements ExceptionMapper<JsonParseException> {
@Override
public Response toResponse(JsonParseException exception) {
return Response
.status(Response.Status.BAD_REQUEST)
// entity ...
.build();
}
}
Я регистрирую свой картограф следующим образом:
@Component
public class OrderServiceResourceConfig extends ResourceConfig {
public OrderServiceResourceConfig() {
packages("com.rmn.gfc.common.providers");
}
}
Я уверен, что регистрация картографа прекрасна, потому что другие пользовательские mappers из этого пакета работают, но один для JsonParseException скрыт стандартным JsonParseExceptionMapper от Джерси.
Как я могу переопределить стандартный Jackson JsonParseExceptionMapper с моей реализацией?
Я нашел решение, которое подходит для меня.
Используйте javax.annotation.Priority
на вашем настраиваемом картографе, чтобы он переопределил картографию по умолчанию Джексона, например:
@Provider
@Priority(1)
public class JsonParseExceptionHandler implements ExceptionMapper<JsonParseException> {
// ...
}
ИЛИ, если вы зарегистрируете компоненты JAX-RS через ResourceConfig, вы можете указать приоритет следующим образом:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(JsonMappingExceptionHandler.class, 1);
register(JsonParseExceptionHandler.class, 1);
// ...
}
}
Нижний номер - самый высокий приоритет. javax.ws.rs.Priorities
имеет определенные предопределенные константы для приоритетов.
JacksonFeature
JacksonFeature
регистрирует сборщики исключений по умолчанию для исключений Джексона, если JacksonJaxbJsonProvider
не зарегистрирован. И это именно то, чего вы не хотите.
См. соответствующие части исходный код:
// Register Jackson. if (!config.isRegistered(JacksonJaxbJsonProvider.class)) { // add the default Jackson exception mappers context.register(JsonParseExceptionMapper.class); context.register(JsonMappingExceptionMapper.class); ... }
JacksonFeature
Класс Spring Boot JerseyAutoConfiguration
зарегистрирует JacksonFeature
, если он находится в пути к классам. См. Соответствующие части исходный код:
@ConditionalOnClass(JacksonFeature.class) @ConditionalOnSingleCandidate(ObjectMapper.class) @Configuration static class JacksonResourceConfigCustomizer { ... @Bean public ResourceConfigCustomizer resourceConfigCustomizer( final ObjectMapper objectMapper) { addJaxbAnnotationIntrospectorIfPresent(objectMapper); return (ResourceConfig config) -> { config.register(JacksonFeature.class); config.register(new ObjectMapperContextResolver(objectMapper), ContextResolver.class); }; } ... }
В качестве обходного пути вы можете зарегистрировать JacksonJaxbJsonProvider
, а затем зарегистрировать свои настраиваемые механизмы отображения (или просто аннотировать их с помощью @Provider
, чтобы автоматически обнаружить Джерси):
@Component
public class OrderServiceResourceConfig extends ResourceConfig {
public OrderServiceResourceConfig() {
packages("com.rmn.gfc.common.providers");
register(JacksonJaxbJsonProvider.class);
// Register other providers
}
}
Посмотрите, что говорится в документации JacksonJaxbJsonProvider
:
Поставщик типа контента JSON автоматически настроен для использования аннотаций Jackson и JAXB (в этом порядке приоритета). В противном случае функционально то же самое, что и
JacksonJsonProvider
.
В качестве альтернативы вы можете избавиться от артефакта jersey-media-json-jackson
и использовать jackson-jaxrs-json-provider
. С этим вы избавитесь от JacksonFeature
, а затем вы сможете зарегистрировать свои собственные механизмы отображения.
Это упоминалось в этом .
Как указано в Kysil Ivan answer, напишите свой собственный блок отображения исключений и придайте ему высокий приоритет, например 1
. Если вы используете автоматическое обнаружение, просто комментируйте его с помощью @Provider
и @Priority
:
@Provider
@Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
...
}
Если вы вручную зарегистрируете своего провайдера, вы можете предоставить провайдеру привязывающий приоритет:
@ApplicationPath("/")
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(JsonParseExceptionMapper.class, 1);
}
}