首页 > 编程语言 >[SprigMVC/SpringBoot] JSON序列化专题之日期序列化问题:接口报Jackson框架错误“InvalidDefinitionException: Java 8 date/time

[SprigMVC/SpringBoot] JSON序列化专题之日期序列化问题:接口报Jackson框架错误“InvalidDefinitionException: Java 8 date/time

时间:2023-05-31 23:22:19浏览次数:66  
标签:... jackson time LocalDateTime import 序列化 com fasterxml

0 序言

今日工作中遇到的一个bug。各位看官且听我娓娓道来。

1 问题描述

请求接口时,service层返回到controller层的数据结构为List<Map<Strig, Object>>,而Map中存在一个key=date,value type=java.time.LocalDateEntry,且日志报如下错误:

InvalidDefinitionException: Java 8 date/time type `java.time.LocalDate` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: cn.xx.bd.dataservice.common.dto.CommonResponse["data"]->cn.xx.bd.dataservice.common.dto.page.v2.PageResponse["records"]->java.util.LinkedList[0]->java.util.HashMap["date"])”

2 问题分析

  • jackson默认不支持java8 LocalDate/LocalDateTime序列化反序列化,那控制台也显示了解决的办法(引入依赖com.fasterxml.jackson.datatype:jackson-datatype-jsr310,并启用对Map中"date"的entry的处理),只不过并不全。

因为 spring-mvc / spring-boot 是使用 jackson 作为 json 序列化反序列化工具的,故只需配置 jackson 即可

3 解决方法

解决方法1 : 类型转换(LocalDate/LocalDateTime --> Date)

将实体类中的LocalDate/LocalDateTime转为Date类型

解决方法2

Step1 引入依赖(com.fasterxml.jackson.datatype:jackson-datatype-jsr310)

<dependency>
	<groupId>com.fasterxml.jackson.datatype</groupId>
	<artifactId>jackson-datatype-jsr310</artifactId>
	<version>2.11.4</version>
</dependency>

spring-boot项目中直接引用:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-json</artifactId>
	<version>2.3.12.RELEASE</version>
</dependency>

Step2 策略1:配置Jackson的序列化/反序列化策略 # 为特定Class Bean的字段指定Jackson的序列化策略

通过注解指定

  • @JsonFormat / @DateTimeFormat / @JsonDeserialize / @JsonSerialize
    @TableField("update_time")
    @ApiModelProperty("更新时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //此注解用来接收字符串类型的参数封装成LocalDateTime类型
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8", shape = JsonFormat.Shape.STRING) //此注解将date类型数据转成字符串响应出去
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)		// 反序列化
    @JsonSerialize(using = LocalDateTimeSerializer.class)		// 序列化
    private LocalDateTime updateTime;

    @TableField("create_time")
    @ApiModelProperty("添加时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") //此注解用来接收字符串类型的参数封装成LocalDateTime类型
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8", shape = JsonFormat.Shape.STRING) //此注解将date类型数据转成字符串响应出去
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)		// 反序列化
    @JsonSerialize(using = LocalDateTimeSerializer.class)		// 序列化
    private LocalDateTime createTime;

Step2 策略2:配置Jackson的序列化/反序列化策略 # 全局配置(MvcConfiguration)

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());
        messageConverter.setObjectMapper(objectMapper);
        converters.add(0, messageConverter);
    }
}

或:

  • Step2.1 JacksonConfiguration
import cn.xx.bd.dataservice.biz.common.constants.Constants;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.springframework.context.annotation.Bean;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

@Configuration
public class JacksonConfiguration {

    @Bean
    public ObjectMapper objectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
        JavaTimeModule javaTimeModule = new JavaTimeModule();

        javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_TIME_FORMAT)));
        javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_TIME_FORMAT)));

        javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_TIME_FORMAT)));
        objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule());
        return objectMapper;
    }
}
  • Step2.2 Constants
public class Constants {
    public static class DateTime {
        /** 默认日期时间格式 */
        public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
        /** 默认日期格式 */
        public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
        /** 默认时间格式 */
        public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    }
}

然后,只需要在实体类中对应的时间类型上使用 @DateTimeFormat@JsonFormat 即可。

解决方法3 以FastJson框架替换Jackson ObjectMapper

用阿里的FastJson替换ObjectMapper

X 参考文献

标签:...,jackson,time,LocalDateTime,import,序列化,com,fasterxml
From: https://www.cnblogs.com/johnnyzen/p/17447639.html

相关文章

  • LocalDateTime、LocalDate、Date的相互转换
    LocalDateTime转LocalDate直接调用toLocalDate()方法LocalDateTimelocalDateTime=LocalDateTime.now();LocalDatelocalDate=localDateTime.toLocalDate();LocalDateTime转Date在LocalDateTime转Date时,需要使用到Java8的几个类ZoneId/ZoneOffset:表示时区ZonedD......
  • Java中序列化和反序列化解释
    在Java中,序列化(Serialization)是指将对象的状态转换为字节流的过程,以便将其保存到文件、在网络中传输或持久化到数据库中。而反序列化(Deserialization)则是将字节流转换回对象的过程,恢复对象的状态。序列化和反序列化主要用于以下场景:1.对象持久化:通过序列化,可以将对象的状态保存......
  • MyBatis+Sharding-JDBC实体类LocalDateTime类型字段查询报SQLFeatureNotSupportedExce
    问题最近协助渠道组开发新需求,封装实现了一个公共模块供不同渠道项目使用。以前各个渠道项目有很多相似的菜单和功能,各自项目里自己的代码实现,本公共模块对新需求的功能点进行抽象,减少重复代码,提高模块复用性和可维护性。目前有2个渠道项目接入了该公共模块,自测时发现其中1个运......
  • 2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程
    2023-05-31:给定一个整数数组A,你可以从某一起始索引出发,跳跃一定次数在你跳跃的过程中,第1、3、5...次跳跃称为奇数跳跃而第2、4、6...次跳跃称为偶数跳跃你可以按以下方式从索引i向后跳转到索引j(其中i<j):在进行奇数跳跃时(如,第1,3,5...次跳跃),你将会跳到索引j使得A[......
  • 2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程
    2023-05-31:给定一个整数数组A,你可以从某一起始索引出发,跳跃一定次数在你跳跃的过程中,第1、3、5...次跳跃称为奇数跳跃而第2、4、6...次跳跃称为偶数跳跃你可以按以下方式从索引i向后跳转到索引j(其中i<j):在进行奇数跳跃时(如,第1,3,5...次跳跃),你将会跳到索引j使得A[i]<=......
  • 【Oracle】Generate the tablespace creation in a time
     此脚本的使用场景是需要使用datapump方式进行数据迁移时,需要在目标数据库上创建对应的表空间,这时对于表空间数量比较多的系统,比如peoplesoft来说,手工单独创建表空间会是一个比较麻烦的事情。以下脚本在源数据库上运行,获取表空间的创建脚本,然后只需对路径相应修改即可使用。......
  • 4.4. 对象序列化与反序列化
    在本节中,我们将详细讨论Java中的对象序列化与反序列化概念、使用方法以及实例。对象序列化是将对象的状态信息转换为字节流的过程,而反序列化则相反,是将字节流恢复为对象的过程。4.4.1为什么需要对象序列化?对象序列化的主要目的是为了在不同的系统间传输对象,或者将对象持久化到......
  • MySQL:一文弄懂时区&time_zone
    https://zhuanlan.zhihu.com/p/448999520你还在被以下问题困扰吗:MySQL的安装规范中应该设置什么时区?JAVA应用读取到的时间和北京时间差了14个小时,为什么?怎么解决?已经运行一段时间的业务,修改MySQL的时区会影响已经存储的时间类型数据吗?迁移数据时会有导致时间类型数据时区......
  • AWR报告参数DB TIME和DB CPU分析
    什么是AWR?ASH(ActiveSessionHistory,活动会话历史信息)、AWR(AutomaticWorkloadRepository,自动负载信息库)、ADDM(AutomaticDatabaseDiagnosticMonitor,数据库自动诊断监视工具)是Oracle性能调整的三把利剑,需要深入地了解,但是面试一般都问得比较简单,主要问到的是AWR。Oracle性能......
  • JDK 8 新时间 DateTimeFormatter
         ......