Spring Boot 升级后 Jackson 序列化不起作用

Posted

技术标签:

【中文标题】Spring Boot 升级后 Jackson 序列化不起作用【英文标题】:Jackson serialization is not working after Spring Boot upgrade 【发布时间】:2018-05-30 10:55:58 【问题描述】:

昨天我开始从 Spring Brussels-SR3 升级到 Spring Brussels-SR6。 Spring Boot 从 1.5.4 开始。到 1.5.9,杰克逊从 2.8.8 到 2.8.10)。我正在使用 HATEOAS 和 HAL 链接。这意味着我的 Jackson 配置如下所示:

@Configuration
public class JacksonConfiguration 

    private static final String SPRING_HATEOAS_OBJECT_MAPPER = "_halObjectMapper";

    @Autowired
    @Qualifier(SPRING_HATEOAS_OBJECT_MAPPER)
    private ObjectMapper springHateoasObjectMapper;

    @Primary
    @Bean(name = "objectMapper")
    ObjectMapper objectMapper() 
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ISO_INSTANT));

        springHateoasObjectMapper.registerModules(javaTimeModule);

        springHateoasObjectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        springHateoasObjectMapper.disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS);

        springHateoasObjectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
        springHateoasObjectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        springHateoasObjectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        springHateoasObjectMapper.enable(SerializationFeature.INDENT_OUTPUT);

        springHateoasObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return springHateoasObjectMapper;
    

这意味着我正在重用_halObjectMapper bean 并添加更多配置。在我开始升级之前它一直有效。

怎么了?

问题在于升级后我的所有序列化自定义和 HAL 约定都没有应用-日期时间格式,缩进 HAL "_links" JSON 字段更改为“链接”......所以 _halObjectMapper 不用于序列化没有了。

任何线索可能是什么问题或我应该在哪里挖掘以找出问题所在?

一些调试后的附加信息:

我发现使用 _halObjectMapper 的 TypeConstrainedMappingJackson2HttpMessageConverter 不再用于转换为 json。原因是它在启动 spring 时没有到达转换器的集合。看起来它不是为 RequestMappingHandlerAdapter bean 创建的,因为当 Jackson2HalModule 已在其他转换器(在本例中为 ProjectingJackson2HttpMessageConverter)中注册时跳过创建的某些条件。

知道可能是什么原因,或者从哪里可以看出为什么 spring boot 启动不同?

更多调试后的附加信息:

我在升级前后看到的区别在于,在升级之前 ProjectingJackson2HttpMessageConverter 填充了 ObjectMapper 的新实例。但是在升级之后,ObjectMapper 是从容器中解析出来的,所以选择了 _halObjectMapper。因此,ProjectingJackson2HttpMessageConverter 与已注册 halModule 的转换器匹配,并且 RequestMappingHandlerAdapter 省略了 TypeConstrainedMappingJackson2HttpMessageConverter 创建。

更有趣的一点是,我又升级了两个微服务。不同的是,一个有相同的问题,一个正在工作。正在工作的那个具有不同的弹簧安全性和 oauth2 设置。 OAuth2RestTemplate 类的 Bean 未在正在工作的微服务中定义。使用 OAuth2RestTemplate 的微服务存在问题。我指出这一点的原因是这两种情况下的初始化行为不同。 OAuth2RestTemplate 休息模板也填充了这些转换器,它可能会影响初始化过程。

临时解决方案

作为临时修补程序,我已将 spring-data-commons 从 1.13.6.RELEASE 降级到 1.13.6.RELEASE。然而,较新的代码对我来说更有意义。

我仍在尝试更好地理解并找出正确的方法

【问题讨论】:

我看不出它在哪里不起作用。 TypeConstrainedMappingJackson2HttpMessageConverter 和 _halObjectMapper 不用于序列化,因此我的任何配置自定义都没有应用。结果是日期时间格式被破坏,没有缩进,“链接”而不是“_links”,链接子结构不是映射而是数组等等...... 你找到解决办法了吗? 不,还没有。我仍然在提到的 spring-data-commons 版本上。你有同样的问题吗? 【参考方案1】:

我不知道它是否对你有帮助,但是我在将 Spring Boot 从版本 2.0.3 升级到 2.0.4 时遇到了非常相似的问题。我仍然不知道究竟是什么导致了这个问题,但解决方案是为我使用的每个模块创建 Bean,而不是替换默认的 ObjectMapper。在您的情况下,它看起来像这样:

    @Configuration
public class JacksonConfiguration 

    @Bean
    JavaTimeModule javaTimeModule () 
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ISO_INSTANT));
        return javaTimeModule;
    

所有功能都可以通过 applications.properties 文件设置,如下所示:

spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES=false
spring.jackson.deserialization.READ_DATE_TIMESTAMPS_AS_NANOSECONDS=false

等等。有关如何配置默认对象映射器而不实际替换它的更多信息,请参阅 https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-customize-the-jackson-objectmapper 和 https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

【讨论】:

以上是关于Spring Boot 升级后 Jackson 序列化不起作用的主要内容,如果未能解决你的问题,请参考以下文章

更新到 Spring Boot 2 后 Jackson 模块未注册

spring boot2 修改默认json解析器Jackson为fastjson

spring boot定制Jackson ObjectMapper,为什么不生效

Spring boot与Jackson ObjectMapper

spring-boot 使用啥版本的 Jackson?

Jackson 在我的 Spring Boot 应用程序中忽略了 spring.jackson.properties