一. 报错信息

最近新开了一个测试项目,使用了Java8的LocalDateTime替换了之前使用的Date类。接口返回结果时,抛出了序列化异常

java.lang.reflect.UndeclaredThrowableException: null
…………
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: 
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: 
cn.xx.dao.common.Back["data"]->cn.xx.dao.data.vo.BmVo["spe"]->
cn.xx.dao.entity.Spe["createTime"])


二. 版本信息

spring boot:2.5.1
jackson-databind:2.12.3

……
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.1</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
……
<dependencies>
      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.12.3</version>
          <scope>compile</scope>
      </dependency>
</dependencies>


三. 解决方法

1. 使用@JsonSerialize + @JsonDeserialize注解
  1. pom加上这两个注解依赖
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.12.3</version>
</dependency>
  1. 在使用LocalDateTime的属性添加两个序列化序列化注解
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime createTime;

这时序列化正常,接口返回了结果,但是很明显不是我们需要的结果:

{
	"createTime": [
		2023,
		3,
		20,
		17,
		34,
		37
	]
}
  1. 加上@JsonFormat来格式化时间,现在就可以正常输出了:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime createTime;

InvalidDefinitionException这个报错,大部分博客提供的思路都是这个,理论上没什么问题,但是实际情况可能需要全局处理如LocalDateTime的时间格式,如果为相关时间字段一个个的加注解,又太过麻烦。所以这种方法只能用于需要处理特定时间格式字段上。

2. 回退Spring Boot版本

鉴于方法A只能作用于局部,而使用Jackson2ObjectMapperBuilderCustomizer时,仍然无法解决InvalidDefinitionException这个异常问题,只能将Spring Boot回退至2.4.x版本问题得到解决
参考Spring Boot 2.5.0 and InvalidDefinitionException: Java 8 date/time type java.time.Instant not supported by default

解决流程

  1. 设置Jackson2ObjectMapperBuilderCustomizer:
@Configuration
public class GlobalDateConfig {
	// 序列化设置时间格式
	private final String formatter = "yyyy-MM-dd HH:mm:ss";
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> {
            DateTimeFormatter localDateTimeFormatter = DateTimeFormatter.ofPattern(formatter);
            //返回时间数据序列化
            builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(localDateTimeFormatter));
            // 接收时间数据序列
            builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(localDateTimeFormatter));
        };
    }
}
  1. 回退Spring Boot版本至2.4.x
……
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.2</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
……
  1. 重启执行问题解决
3. 回退jackson版本

Spring Boot 2.4.x使用的是jackson 2.11.x
Spring Boot 2.5.x使用的是jackson 2.12.x
参考:Spring Boot 2.5.0 and InvalidDefinitionException: Java 8 date/time type java.time.Instant not supported by default

  1. 无须修改Spring Boot版本,并显式指定jackson版本(2.13也报这个错误原因可以参考这里a change in Jackson 2.12comment of 2.4 and 2.5
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.11.2</version>
</dependency>
  1. 使用上文的GlobalDateConfig配置重启执行,问题解决


四. 一些尝试(未解决问题)

根据Spring Boot的讨论和Stack overflow的一些解决方法做了一些尝试,但是均未成功解决问题。

1. 向自定义ObjectMapper Bean中注册JavaTimeModule

我的项目中,并不存在这种自定义ObjectMapper且将其设置全局Bean的情况。

如果存在定义ObjectMapper Bean的情况下,需要注册处理java8时间序列化的类:JavaTimeModule(或者Jdk8Module)

@Bean
@Primary
public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    return objectMapper;
}

或者:

@Bean
@Primary
public ObjectMapper objectMapper() {
    return JsonMapper.builder()
            .addModule(new JavaTimeModule())
            .build();
}

或者

@Resource
private Jackson2ObjectMapperBuilder mapperBuilder;

@Bean
@Primary
public ObjectMapper objectMapper() {
    ObjectMapper build = mapperBuilder.build();
    objectMapper.registerModule(new JavaTimeModule());
    return objectMapper;
}

几种情况没遇到过,不知道是否可行。总之这里对我的代码不起作用。
此外,JavaTimeModule还支持定义格式

DateTimeFormatter localDateTimeFormatter = DateTimeFormatter.ofPattern(formatter);
// 添加Java8时间序列化反序列
JavaTimeModule javaTimeModule = new JavaTimeModule();
//返回时间数据序列
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(localDateTimeFormatter));
//接收时间数据序列
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(localDateTimeFormatter));

2. 设置Jackson2ObjectMapperBuilder类
  1. 设置Jackson2ObjectMapperBuilder类,控制序列化和反序列操作

很明显,这个就是实现一个Jackson2ObjectMapperBuilderCustomizer类,与上文中的方法jackson2ObjectMapperBuilderCustomizer作用相同。这里也无法解决开头的问题。

@Configuration
public class GlobalDateConfig implements Jackson2ObjectMapperBuilderCustomizer {
    private final String formatter = "yyyy-MM-dd HH:mm:ss";
    @Override
    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
        jacksonObjectMapperBuilder.simpleDateFormat(formatter)
                .modules(new JavaTimeModule())
                .serializationInclusion(JsonInclude.Include.ALWAYS)
                .failOnEmptyBeans(false)
                .failOnUnknownProperties(false)
                .featuresToEnable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN)
                .featuresToEnable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
    }
}

参考

Spring Boot 2.5.0 and InvalidDefinitionException: Java 8 date/time type java.time.Instant not supported by default

原文地址:https://blog.csdn.net/HO1_K/article/details/129675462

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_21024.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注