Spring Boot 4 自定义序列化器配置与实战
适用版本:Spring Boot 4.0+
背景:为什么需要重写自定义序列化器?
在 Spring Boot 3.x 及更早版本中,项目普遍使用 Jackson 2(com.fasterxml.jackson)作为默认的 JSON 序列化/反序列化库。然而,Spring Boot 4.0 开始全面转向 Jackson 3(tools.jackson),这是由 FasterXML 团队主导的新一代 Jackson 版本。
这一重大变更虽然带来了性能和模块化的提升,但也破坏了大量原有基于 Jackson 2 的自定义序列化器/反序列化器代码。许多团队在升级后发现:
- 自定义
JsonSerializer/JsonDeserializer不再生效; ObjectMapper相关配置失效;- 日期格式、枚举处理等逻辑异常。
为解决这个问题,Spring Boot 4 提供了新的注解机制 —— @JacksonComponent,并要求开发者使用 Jackson 3 的新包路径与 API。
本文将通过一个实际案例,展示如何在 Spring Boot 4 中正确编写和注册自定义的 LocalDate、LocalTime 和 LocalDateTime 序列化器。
核心变化对比(Jackson 2 → Jackson 3)
| 内容 | Jackson 2 | Jackson 3 |
|---|---|---|
| 包路径 | com.fasterxml.jackson.core | tools.jackson.core |
| ObjectMapper | com.fasterxml.jackson.databind.ObjectMapper | tools.jackson.databind.json.JsonMapper |
| 注册方式 | 手动注册 Module 或使用 @JsonComponent(已废弃) | 使用 @JacksonComponent |
| 官方推荐 | 已标记为 deprecated | 全面支持 |
📌 注意:Spring Boot 4 不再支持
@JsonComponent,必须改用@JacksonComponent。
实战:Spring Boot 4 自定义时间类型序列化器
以下是一个完整的、可直接使用的配置类,用于统一处理 LocalDate、LocalTime 和 LocalDateTime 的 JSON 序列化与反序列化。
package com.example.config;
import org.springframework.boot.jackson.JacksonComponent;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.JsonParser;
tools.jackson.databind.*;
java.time.LocalDate;
java.time.LocalDateTime;
java.time.LocalTime;
java.time.format.DateTimeFormatter;
{
DateTimeFormatter.ofPattern();
DateTimeFormatter.ofPattern();
DateTimeFormatter.ofPattern();
<LocalDate> {
JacksonException {
g.writeString(v != ? DATE_FORMATTER.format(v) : );
}
}
<LocalDate> {
LocalDate JacksonException {
p.getValueAsString();
s == || s.isEmpty() ? : LocalDate.parse(s, DATE_FORMATTER);
}
}
<LocalTime> {
JacksonException {
g.writeString(v != ? TIME_FORMATTER.format(v) : );
}
}
<LocalTime> {
LocalTime JacksonException {
p.getValueAsString();
s == || s.isEmpty() ? : LocalTime.parse(s, TIME_FORMATTER);
}
}
<LocalDateTime> {
JacksonException {
g.writeString(v != ? DATE_TIME_FORMATTER.format(v) : );
}
}
<LocalDateTime> {
LocalDateTime JacksonException {
p.getValueAsString();
s == || s.isEmpty() ? : LocalDateTime.parse(s, DATE_TIME_FORMATTER);
}
}
}


