spring boot 4.* 自定義序列化器的實(shí)現(xiàn)
一、背景說明
在Spring Boot 4.*版本升級過程中,我們團(tuán)隊(duì)及不少開發(fā)者發(fā)現(xiàn)原有基于Jackson的自定義序列化器/反序列化器全部失效。經(jīng)排查,核心原因是Spring Boot 4.0對Jackson的集成方式做了重大調(diào)整,尤其是自定義序列化組件的注冊機(jī)制、基類繼承體系發(fā)生了變化,導(dǎo)致舊版本中基于StdSerializer/StdDeserializer的實(shí)現(xiàn)方式不再適用。
為解決這一問題,我們封裝了適配Spring Boot 4.*的Jackson自定義序列化配置類,本文將詳細(xì)講解該配置的實(shí)現(xiàn)原理、使用方式,并結(jié)合官方文檔說明版本變更的核心點(diǎn)。
二、核心變更(官方文檔參考)
Spring Boot 4.0對JSON處理的Jackson集成做了關(guān)鍵調(diào)整,官方文檔鏈接:https://www.spring-doc.cn/spring-boot/4.0.0/reference_features_json.html
核心變更點(diǎn):
- 序列化/反序列化基類調(diào)整:不再推薦直接繼承
StdSerializer/StdDeserializer,而是新增ValueSerializer/ValueDeserializer作為核心基類; - 組件注冊方式優(yōu)化:新增
@JacksonComponent注解,替代舊版本的手動注冊方式,實(shí)現(xiàn)序列化組件的自動掃描和注冊; - 類型適配性增強(qiáng):對Java 8時(shí)間類型(
LocalDate/LocalTime/LocalDateTime)的序列化支持做了重構(gòu),舊版自定義序列化邏輯需適配新基類。
三、適配Spring Boot 4.*的自定義序列化實(shí)現(xiàn)
以下是完整的Jackson配置類,實(shí)現(xiàn)了Java 8時(shí)間類型的自定義序列化/反序列化,適配Spring Boot 4.*版本的核心規(guī)范。
3.1 完整代碼實(shí)現(xiàn)
package com.auy.conf;
import org.springframework.boot.jackson.JacksonComponent;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.JsonParser;
import tools.jackson.databind.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
* Spring Boot 4 兼容的 Jackson 配置
* 核心適配點(diǎn):
* 1. 繼承新版ValueSerializer/ValueDeserializer基類
* 2. 使用@JacksonComponent注解實(shí)現(xiàn)組件自動注冊
* 3. 適配Java 8時(shí)間類型的序列化/反序列化邏輯
*/
@JacksonComponent//:標(biāo)記為Jackson組件,Spring Boot 4會自動掃描并注冊
public class JacksonConfig {
// 全局時(shí)間格式配置(從AuyConfig讀取自定義格式,可根據(jù)業(yè)務(wù)調(diào)整為固定格式)
public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(AuyConfig.get().getDateTimeFormat().getDatePattern());
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(AuyConfig.get().getDateTimeFormat().getTimePattern());
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(AuyConfig.get().getDateTimeFormat().getDateTimePattern());
/**
* LocalDate 自定義序列化器
*/
public static class CustomLocalDateSerializer extends ValueSerializer<LocalDate> {
@Override
public void serialize(LocalDate v, JsonGenerator g, SerializationContext c) throws JacksonException {
// 序列化邏輯:LocalDate轉(zhuǎn)指定格式的字符串,null值返回null
g.writeString(v != null ? DATE_FORMATTER.format(v) : null);
}
}
/**
* LocalDate 自定義反序列化器
*/
public static class CustomLocalDateDeserializer extends ValueDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext c) throws JacksonException {
// 反序列化邏輯:字符串轉(zhuǎn)LocalDate,空值返回null
String s = p.getValueAsString();
return s == null || s.isEmpty() ? null : LocalDate.parse(s, DATE_FORMATTER);
}
}
/**
* LocalTime 自定義序列化器
*/
public static class CustomLocalTimeSerializer extends ValueSerializer<LocalTime> {
@Override
public void serialize(LocalTime v, JsonGenerator g, SerializationContext c) throws JacksonException {
g.writeString(v != null ? TIME_FORMATTER.format(v) : null);
}
}
/**
* LocalTime 自定義反序列化器
*/
public static class CustomLocalTimeDeserializer extends ValueDeserializer<LocalTime> {
@Override
public LocalTime deserialize(JsonParser p, DeserializationContext c) throws JacksonException {
String s = p.getValueAsString();
return s == null || s.isEmpty() ? null : LocalTime.parse(s, TIME_FORMATTER);
}
}
/**
* LocalDateTime 自定義序列化器
*/
public static class CustomLocalDateTimeSerializer extends ValueSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime v, JsonGenerator g, SerializationContext c) throws JacksonException {
g.writeString(v != null ? DATE_TIME_FORMATTER.format(v) : null);
}
}
/**
* LocalDateTime 自定義反序列化器
*/
public static class CustomLocalDateTimeDeserializer extends ValueDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext c) throws JacksonException {
String s = p.getValueAsString();
return s == null || s.isEmpty() ? null : LocalDateTime.parse(s, DATE_TIME_FORMATTER);
}
}
}
3.2 代碼關(guān)鍵說明
基類適配:
- 序列化器繼承
ValueSerializer<T>,反序列化器繼承ValueDeserializer<T>(Spring Boot 4.*推薦的新版基類); - 重寫核心方法:序列化器重寫
serialize,反序列化器重寫deserialize,方法參數(shù)與舊版兼容,但基類體系不同。
- 序列化器繼承
組件注冊:
- 使用
@JacksonComponent注解標(biāo)記基類(會將內(nèi)部類全部注冊)或者內(nèi)部靜態(tài)類(只注冊標(biāo)記的類),Spring Boot 4會自動掃描該注解并將序列化/反序列化器注冊到Jackson容器中,無需手動配置ObjectMapper; - 該注解替代了舊版本中
@Bean注冊SimpleModule的方式,簡化了配置流程。
- 使用
時(shí)間格式配置:
- 從
AuyConfig讀取自定義的時(shí)間格式(日期、時(shí)間、日期時(shí)間),也可直接替換為固定格式(如yyyy-MM-dd); - 處理null值和空字符串:反序列化時(shí)對空值做兼容,避免解析異常;序列化時(shí)null值返回null,符合JSON規(guī)范。
- 從
包路徑注意:
- Jackson核心類的包路徑為
tools.jackson.*(Spring Boot 4.*調(diào)整后的路徑,舊版為com.fasterxml.jackson.*),需確保依賴包版本匹配。
- Jackson核心類的包路徑為
四、使用說明
4.1 依賴要求
確保Spring Boot版本為4.*,且Jackson相關(guān)依賴由Spring Boot父工程管理,無需手動指定版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
<relativePath/>
</parent>
<dependencies>
<!-- JSON核心依賴(包含Jackson,一般不需要引入,web依賴會自動包含它) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jackson</artifactId>
</dependency>
</dependencies>
4.2 配置生效條件
JacksonConfig類需放在Spring Boot的掃描路徑下(如com.auy.conf包被@SpringBootApplication掃描);@JacksonComponent注解會自動觸發(fā)組件注冊,無需額外配置;AuyConfig需確保能正常獲取時(shí)間格式配置,若無需動態(tài)配置,可直接替換為固定格式:// 示例:固定格式配置 public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
4.3 驗(yàn)證方式
編寫測試類,驗(yàn)證時(shí)間類型的序列化/反序列化是否符合預(yù)期:
import com.auy.conf.JacksonConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDateTime;
@SpringBootTest
public class JacksonSerializerTest {
@Autowired
private ObjectMapper objectMapper;
@Test
public void testLocalDateTimeSerializer() throws Exception {
LocalDateTime now = LocalDateTime.now();
// 序列化
String json = objectMapper.writeValueAsString(now);
System.out.println("序列化結(jié)果:" + json);
// 反序列化
LocalDateTime parsed = objectMapper.readValue(json, LocalDateTime.class);
System.out.println("反序列化結(jié)果:" + parsed);
}
}
五、擴(kuò)展適配其他類型
若需適配其他自定義類型(如枚舉、自定義VO),可參考以下模板:
@JacksonComponent
public static class CustomEnumSerializer extends ValueSerializer<YourEnum> {
@Override
public void serialize(YourEnum v, JsonGenerator g, SerializationContext c) throws JacksonException {
// 自定義枚舉序列化邏輯,如返回枚舉的描述值
g.writeString(v != null ? v.getDesc() : null);
}
}
@JacksonComponent
public static class CustomEnumDeserializer extends ValueDeserializer<YourEnum> {
@Override
public YourEnum deserialize(JsonParser p, DeserializationContext c) throws JacksonException {
String s = p.getValueAsString();
// 自定義枚舉反序列化邏輯
return s == null ? null : YourEnum.getByDesc(s);
}
}
六、常見問題解決
序列化器不生效:
- 檢查
@JacksonComponent注解是否添加; - 確認(rèn)
JacksonConfig在Spring掃描路徑下; - 檢查Jackson包路徑是否為
tools.jackson.*(Spring Boot 4.*調(diào)整后的路徑)。
- 檢查
時(shí)間格式解析異常:
- 確認(rèn)
DATE_FORMATTER/TIME_FORMATTER/DATE_TIME_FORMATTER的格式與輸入字符串匹配; - 反序列化時(shí)增加異常捕獲(可選),適配多格式場景。
- 確認(rèn)
依賴沖突:
- 排除舊版Jackson依賴(
com.fasterxml.jackson.*); - 確保Spring Boot父工程版本為4.*。
- 排除舊版Jackson依賴(
七、總結(jié)
Spring Boot 4.*對Jackson的集成調(diào)整核心在于基類和注冊方式的優(yōu)化,通過繼承ValueSerializer/ValueDeserializer并使用@JacksonComponent注解,可快速適配新版序列化邏輯。本文提供的JacksonConfig類已實(shí)現(xiàn)Java 8時(shí)間類型的完整適配,可直接復(fù)用或擴(kuò)展至其他自定義類型,解決升級后序列化器失效的問題。
到此這篇關(guān)于spring boot 4.* 自定義序列化器的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)springboot 自定義序列化器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring中事務(wù)管理的四種方法(銀行轉(zhuǎn)賬為例)
這篇文章主要給大家介紹了關(guān)于Spring中事務(wù)管理的四種方法,文中是以銀行轉(zhuǎn)賬為例,通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05
寧可用Lombok也不把成員設(shè)置為public原理解析
這篇文章主要為大家介紹了寧可用Lombok也不把成員設(shè)置為public原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
mybatis plus generator 根據(jù)數(shù)據(jù)庫自動生成實(shí)體類的實(shí)現(xiàn)示例
本文主要介紹了mybatis plus generator 根據(jù)數(shù)據(jù)庫自動生成實(shí)體類的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
Java中的日期和時(shí)間類以及Calendar類用法詳解
這篇文章主要介紹了Java中的日期和時(shí)間類以及Calendar類用法詳解,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09

