本文記錄一次在 Spring Boot 項目中,DTO 字段明明有值,反序列化后卻是 null 的問題。最終發現并不是常見的 JSON 工具庫 Bug,而是隱藏在 setter 命名大小寫規則中的坑。
💻 背景介紹
技術棧如下:
Spring Boot:
2.2.3.RELEASE
Java:
1.8
JSON 序列化:默認使用 Jackson,部分地方使用 Fastjson
使用了
Lombok
的@Data
注解簡化 DTO 編寫
業務中,前端提交如下 JSON 數據:
{"cPlanId": "CP-202507150001"
}
DTO 如下:
@Data
public class CPlanIdRequestDTO implements Serializable {@NotBlank(message = "不能為空")private String cPlanId;
}
🧪 問題表現
后端接收到的參數綁定結果中,cPlanId == null
。但是 JSON 明明是正確的,而且 DTO 上也有 @Data
自動生成 getter/setter。
嘗試如下方式:
public void setCPlanId(String cPlanId) {this.cPlanId = cPlanId;
}
→ 依然無效
嘗試這樣寫:
public void setcPlanId(String cPlanId) {this.cPlanId = cPlanId;
}
→ 反而成功了!
🔍 排查過程
? Step 1:確認 JSON 數據沒問題
接口調試工具(如 Postman、Apifox)發送參數正常,字段名也符合預期:"cPlanId"
。
? Step 2:確認使用的 JSON 庫
項目中同時存在:
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>
但是在未手動配置 FastJsonHttpMessageConverter
的前提下,Spring Boot 默認用的是 Jackson。
? Step 3:查看 ObjectMapper 配置
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
→ 沒有特殊命名策略。
🎯 真正的問題原因:setter 方法名大小寫
根據 JavaBean 規范:
private String cPlanId;
應該對應setCPlanId(String)
,不是setcPlanId(String)
Jackson 遵循此規范
Fastjson 則更“靈活”,會根據字段名匹配
setcPlanId()
,哪怕違反 JavaBean 規范
但我們項目中,有可能某個地方通過工具類(如 JsonUtils)手動調用了 Fastjson 來解析參數,繞過了 Spring MVC 默認的 Jackson。
? 解決方案
? 推薦方式 1:統一命名,手動寫標準方法
public class CPlanIdRequestDTO implements Serializable {private String cPlanId;public void setcPlanId(String cPlanId) {this.cPlanId = cPlanId;}
}
? 推薦方式 2:加注解雙兼容
@JsonProperty("cPlanId")
@JSONField(name = "cPlanId")
private String cPlanId;
🧠 思考與總結
案例 | 結果 |
---|---|
@Data 自動生成 + Jackson | ?? 成功 |
setCPlanId() (規范寫法) + Fastjson | ? 有時失敗 |
setcPlanId() (非規范) + Fastjson | ?? 成功 |
未加 setter + Fastjson | ? 很可能失敗 |
DTO 中添加注解 | ?? 通用成功 |
本次問題提醒我們:
? 保持 setter 方法命名符合 JavaBean 規范
? 項目中盡量統一使用一種 JSON 庫(建議 Jackson)
? 若存在多種工具(如 Fastjson 工具類、Jackson 配置),注意行為差異
? 接口 DTO 中的重要字段,手動加
getter/setter
更保險
一個字段無法反序列化的 bug,背后牽涉 JSON 工具的默認策略、setter 方法的命名大小寫、工具類使用方式、項目配置混雜等多個維度。
?