本文记录一次在 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 方法的命名大小写、工具类使用方式、项目配置混杂等多个维度。