Spring Boot升级到2.x,Jackson对Date时间类型序列化的变化差点让项目暴雷【享学Spring Boot】(上)

简介: Spring Boot升级到2.x,Jackson对Date时间类型序列化的变化差点让项目暴雷【享学Spring Boot】(上)

前言


在阅读本文之前,建议你已经掌握了Jackson的知识以及它的Spring、Spring Boot下的集成和运用。


说明:若不熟悉Jackson,请务必参阅我的专栏[享学Jackson](单击这里电梯直达),该专栏有可能是全网最好、最全的完整教程。


本文讲述的是本人在生产上的一个真实案例,分享给大家,避免你采坑。它的大背景是项目需要从Spring Boot1.x升级到2.x版本,升上去之后由于Jackson对时间类型序列化的变化,使得多个项目险些暴雷,幸好本人对Jackson很了解所以迅速定位并且解决问题,及时止损。


说明:因为我写这个是个脚手架,供给多个团队使用。在Jackson这点上没有考虑好向下兼容性导致多个项目差点暴雷,幸好及时止损。


正文


大家都知道,Spring Boot2.x对1.x版本是不向下兼容的,如果你曾经做过升级、或者Spring MVC -> Spring Boot2.x的迁移,相信你或多或少遇到过些麻烦。确实,Spring Boot的API设计者、代码编写者的“实力”是不如Spring Framework的,所以即使是同体系的1.x -> 2.x都会遇到不少问题(这里不包括编译问题)。


本文的关注点是Spring Boot不同大版本下Jackson对日期/时间类型的序列化问题。据我调查和了解,该问题也是很多同学的痛点,所以相信本文能帮助到你避免采坑。

Spring Boot 1.x和2.x差异


Spring Boot因它经常升级而不具有向下兼容性而向来“臭名昭著”,其中大版本号升级1.x升级到2.x尤为凸显,本文将采用这两个不同大版本,对其对日期/时间类型序列化表现作出对比。使用的Spring Boot版本号公式如下:


  • 1.x版本号是:1.5.22.RELEASE(1.x版本的最后一个版本,并且在2019.8.1宣布停止维护)
  • 2.x版本号是:2.0.0.RELEASE(2018.3.1发布)


说明:本文使用2.0.0.RELEASE版本,而非使用和享学Jackson 专栏一致的版本号,是想强调说明:这个差异是发生在1.x和2.x交替之时,而非2.x之后的变化。


Jar包差异


不同的Spring Boot导入的Jar版本是不一样的,这个差异在大版本号之间也不容忽略。


1.x版本:

image.png


2.x版本:

image.png



小总结


从截图方面可看出,Jar包导入方面差异还是挺大的:


  • 1.x只自动给你导入了三大核心包,三个常用三方包一个都木有帮你导入
  • 1.x版本最低基于JDK6构建的,所以默认其它三方包就没导入。但若你是基于JDK8构建的,强烈建议你手动导入常用三方包
  • 2.x通过web带入了spring-boot-starter-json这个启动器,该启动器管理着“所有”有用的Jackson相关Jar包,不仅仅是核心包
  • 2.x版本对JDK的最低要求是JDK8,所以默认就给你带上这三个常用模块是完全合理的
  • 1.x使用的Jackson版本号是:2.8.11.3;2.x使用的Jackson版本号是2.9.4;版本差异上并不大,可忽略


ObjectMapper表现


我们知道Spring Boot默认情况下是向容器内放置了一个ObjectMapper实例的,因此我们可以直接使用,下面案例就是这样做的。


公用代码:


@Autowired
ObjectMapper objectMapper;
@Test
public void contextLoads() throws JsonProcessingException {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("date", new Date());
    map.put("timestamp", new Timestamp(System.currentTimeMillis()));
    map.put("localDateTime", LocalDateTime.now());
    map.put("localDate", LocalDate.now());
    map.put("localTime", LocalTime.now());
    map.put("instant", Instant.now());
    System.out.println(objectMapper.writeValueAsString(map));
}



在不同的Spring Boot版本上的输出,表现如下:

1.x版本:


{
    "date":1580897613003,
    "timestamp":1580897613003,
    "localDateTime":{
        "dayOfMonth":5,
        "dayOfWeek":"WEDNESDAY",
        "month":"FEBRUARY",
        "year":2020,
        "hour":18,
        "minute":13,
        "nano":9000000,
        "second":33,
        "dayOfYear":36,
        "monthValue":2,
        "chronology":{
            "id":"ISO",
            "calendarType":"iso8601"
        }
    },
    "localDate":{
        "year":2020,
        "month":"FEBRUARY",
        "dayOfMonth":5,
        "dayOfWeek":"WEDNESDAY",
        "era":"CE",
        "chronology":{
            "id":"ISO",
            "calendarType":"iso8601"
        },
        "dayOfYear":36,
        "leapYear":true,
        "monthValue":2
    },
    "localTime":{
        "hour":18,
        "minute":13,
        "second":33,
        "nano":9000000
    },
    "instant":{
        "epochSecond":1580897613,
        "nano":9000000
    }
}


2.x版本:


{
    "date":"2020-02-05T10:15:36.520+0000",
    "timestamp":"2020-02-05T10:15:36.520+0000",
    "localDateTime":"2020-02-05T18:15:36.527",
    "localDate":"2020-02-05",
    "localTime":"18:15:36.527",
    "instant":"2020-02-05T10:15:36.527Z"
}


小总结

1.x的执行效果同:


@Test
public void fun1() throws JsonProcessingException {
    ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("date", new Date());
    map.put("timestamp", new Timestamp(System.currentTimeMillis()));
    map.put("localDateTime", LocalDateTime.now());
    map.put("localDate", LocalDate.now());
    map.put("localTime", LocalTime.now());
    map.put("instant", Instant.now());
    System.out.println(mapper.writeValueAsString(map));
}


2.x的执行效果同:

@Test
public void fun1() throws JsonProcessingException {
    ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  ... // 省略map(同上)
    System.out.println(mapper.writeValueAsString(map));
}


可以看到,他们的差异仅在一个特征值SerializationFeature.WRITE_DATES_AS_TIMESTAMPS是否开启。然后Spring Boot不同版本上对此值有差异:


  • 1.x下此特征开启(这是Jackson的默认行为,是开启的)
  • 2.x下此特征关闭



相关文章
|
4月前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
5月前
|
Java API 开发者
JDK8到JDK17版本升级的新特性问题之SpringBoot选择JDK17作为最小支持的Java lts版本意味着什么
JDK8到JDK17版本升级的新特性问题之SpringBoot选择JDK17作为最小支持的Java lts版本意味着什么
162 0
JDK8到JDK17版本升级的新特性问题之SpringBoot选择JDK17作为最小支持的Java lts版本意味着什么
|
7月前
|
JSON Java API
jackson序列化和反序列化中的注解和扩展点大全【收藏】
jackson序列化和反序列化中的注解和扩展点大全【收藏】
|
7月前
|
NoSQL Redis
redis使用jackson序列化数据配置文件
redis使用jackson序列化数据配置文件
128 5
|
7月前
|
监控 Java 开发者
Spring Boot 3 升级全解析:新特性与改进点一网打尽
Spring Boot 3 升级全解析:新特性与改进点一网打尽
|
7月前
|
Java
springboot解决jackson序列化Long类型精度失效问题
springboot解决jackson序列化Long类型精度失效问题
155 0
|
8月前
|
移动开发 前端开发 NoSQL
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
366 0
|
8月前
|
JSON Java 数据格式
nbcio-boot升级springboot、mybatis-plus和JSQLParser后的LocalDateTime日期json问题
nbcio-boot升级springboot、mybatis-plus和JSQLParser后的LocalDateTime日期json问题
98 0
|
2月前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
2月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。