我的项目使用 Spring Boot + Jersey 2。
我为 JsonParseException 创建了自定义 Jackson 映射器,但它没有被调用,而是使用了标准的 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");
}
}
我确信映射器注册很好,因为这个包中的其他自定义映射器正在工作,但 JsonParseException 的一个映射器被 Jersey 标准 JsonParseExceptionMapper 遮住了。
我如何用我的实现覆盖标准的 Jackson JsonParseExceptionMapper?
最佳答案
你可以怪JacksonFeature
JacksonFeature
如果 JacksonJaxbJsonProvider
,为 Jackson 异常注册默认异常映射器未注册。而这正是你不想要的。
相关部分见source code :
// Register Jackson. if (!config.isRegistered(JacksonJaxbJsonProvider.class)) { // add the default Jackson exception mappers context.register(JsonParseExceptionMapper.class); context.register(JsonMappingExceptionMapper.class); ... }
Spring Boot 注册
JacksonFeature
Spring Boot 的
JerseyAutoConfiguration
类将注册 JacksonFeature
如果它在类路径上。相关部分见source code :@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
注释它们以被 Jersey 自动发现):@Component
public class OrderServiceResourceConfig extends ResourceConfig {
public OrderServiceResourceConfig() {
packages("com.rmn.gfc.common.providers");
register(JacksonJaxbJsonProvider.class);
// Register other providers
}
}
查看文档对
JacksonJaxbJsonProvider
的说明:JSON content type provider automatically configured to use both Jackson and JAXB annotations (in that order of priority). Otherwise functionally same as
JacksonJsonProvider
.
替代方案
或者,您可以摆脱
jersey-media-json-jackson
Artifact 和使用 jackson-jaxrs-json-provider
反而。有了这个,你将摆脱 JacksonFeature
然后你可以注册你自己的异常映射器。这是在这个answer中提到的.
什么似乎是正确的解决方案
请参阅以下来自 JAX-RS 2.1 specification 的引用:
4.1.3 Priorities
Application-supplied providers enable developers to extend and customize the JAX-RS runtime. Therefore, an application-supplied provider MUST always be preferred over a pre-packaged one if a single one is required.
Application-supplied providers may be annotated with
@Priority
. If two or more providers are candidates for a certain task, the one with the highest priority is chosen: the highest priority is defined to be the one with the lowest value in this case. That is,@Priority(1)
is higher than@Priority(10)
. If two or more providers are eligible and have identical priorities, one is chosen in an implementation dependent manner.The default priority for all application-supplied providers is
javax.ws.rs.Priorities.USER
. The general rule about priorities is different for filters and interceptors since these providers are collected into chains.
正如 Kysil Ivan 的 answer 中指出的那样, 编写自己的异常映射器并赋予高优先级,例如
1
.如果你使用自动发现,只需用 @Provider
注释它和 @Priority
.@Provider
@Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
...
}
如果您手动注册您的提供商,您可以 give your provider a binding priority :
@ApplicationPath("/")
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(JsonParseExceptionMapper.class, 1);
}
}
关于java - Jackson JsonParseExceptionMapper 和 JsonMappingExceptionMapper 阴影自定义映射器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45478512/