Spring Boot中Jackson处理java.time.Duration序列化失败求助
看起来你遇到的是Jackson对Java 8 Duration类型处理不当导致的反序列化错误。咱们一步步来搞定这个问题:
错误原因分析
你当前的请求体用的是Jackson内部对Duration的表示结构(包含seconds、nano、units字段),但Spring默认的Jackson配置(如果没引入JSR310模块)或者默认序列化规则,并不认识这种结构——它期望的是符合ISO-8601标准的Duration字符串(比如PT1H30M),所以才会抛出"Failed to read H..."这类反序列化失败的错误。
解决方案
1. 引入Jackson的Java 8时间模块
首先,确保项目依赖里包含Jackson对Java 8日期时间类型的支持模块,因为Duration属于Java 8新增的时间API:
如果是Maven项目,在pom.xml里添加:
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <!-- 版本建议和项目中Jackson核心版本保持一致 --> <version>2.15.2</version> </dependency>
Gradle项目的话:
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2'
2. 配置Jackson正确处理Duration
接下来需要让Jackson把Duration序列化为ISO格式字符串,同时也能从ISO字符串反序列化。有两种实现方式:
方式一:全局配置(推荐)
创建Jackson配置类,让配置全局生效:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JacksonTimeConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 注册Java 8时间模块 objectMapper.registerModule(new JavaTimeModule()); // 禁用将Duration序列化为时间戳,改用ISO格式字符串 objectMapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS); return objectMapper; } }
方式二:字段级注解配置
如果只想针对A类里的availTime字段生效,可以在字段上添加注解:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.DurationSerializer; import java.time.Duration; public class A { @JsonSerialize(using = DurationSerializer.class) @JsonDeserialize(using = DurationDeserializer.class) private Duration availTime; // 别忘了添加getter和setter方法 public Duration getAvailTime() { return availTime; } public void setAvailTime(Duration availTime) { this.availTime = availTime; } }
3. 修改请求体为标准ISO格式
现在你需要把请求体改成符合ISO-8601的Duration字符串,替换原来的内部结构:
{ "availTime": "PT1H30M" }
这样Spring就能正确反序列化请求体,同时响应也会返回你期望的{"availTime": "PT1H30M"}格式。
补充说明
Jackson的JavaTimeModule默认基于ISO标准字符串处理Duration,你之前传的包含seconds、nano的结构是Jackson内部的非标准序列化格式,不是REST服务交互的推荐格式,所以更建议使用标准ISO字符串来传递Duration数据。
内容的提问来源于stack exchange,提问作者Chris Antonopoulos

