java - Jackson JsonParseExceptionMapper 和 JsonMappingExceptionMapper 阴影自定义映射器

标签 java spring-boot jersey

我的项目使用 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/

相关文章:

java - java字符串模板的最佳实践是什么? Apache Commons StrSubstitutor 是正确的选择工具吗?

java - 在 Jersey 中返回 XML/JSON

spring-boot - 使用 Gradle 和 Spring Boot Gradle 插件时,如何从不同的模块复制 Spring Boot 重新打包的 jar?

java - 任何众所周知的 Java 库,仅返回 REST API 请求的字段

java - 如何将 url 中的查询字符串传递的值传递到 spring Controller 中?

REST:长时间运行操作中处理错误,如何通知客户端?

java - 泽西 RESTful 服务,错误 500

java - 如何使用 Java 解析 Atop(Linux 实用程序)的原始文件?

java - apache Spark 的 CountVectorizerModel 错误 - Java API

java - 在 NetBeans 8 中自定义从数据库生成的实体