记录jackson解析出错
Jackson 属性名大小写 Bug 记录
问题描述
在前后端交互过程中,前端传递的 JSON 字段名为驼峰风格(如 qTitle
),后端 Java 实体类字段名也为驼峰(如 private String qTitle;
)。
但在反序列化时,发现后端接收到的 qTitle
字段始终为 null
,导致如 @NotBlank(message = "问卷标题不能为空")
校验失败。
现象
- 前端请求体:
{"qTitle": "2024年员工满意度调查问卷",... }
- 后端实体类:
public class QuestionnaireCreateRequest {@NotBlank(message = "问卷标题不能为空")private String qTitle;// ... }
- 实际后端接收到的
qTitle
字段为null
,触发校验异常。
排查过程
- 确认前后端字段名一致,均为驼峰。
- 查看 Jackson 源码,定位到
legacyManglePropertyName
方法:/*** Method called to figure out name of the property, given * corresponding suggested name based on a method or field name.** @param basename Name of accessor/mutator method, not including prefix* ("get"/"is"/"set")*/protected String legacyManglePropertyName(final String basename, final int offset){final int end = basename.length();if (end == offset) { // empty name, nopereturn null;}char c = basename.charAt(offset);// 12-Oct-2020, tatu: Additional configurability; allow checking that// base name is acceptable (currently just by checking first character)if (_baseNameValidator != null) {if (!_baseNameValidator.accept(c, basename, offset)) {return null;}}// next check: is the first character upper case? If not, return as ischar d = Character.toLowerCase(c);if (c == d) {return basename.substring(offset);}// otherwise, lower case initial chars. Common case first, just one charStringBuilder sb = new StringBuilder(end - offset);sb.append(d);int i = offset+1;for (; i < end; ++i) {c = basename.charAt(i);d = Character.toLowerCase(c);if (c == d) {sb.append(basename, i, end);break;}sb.append(d);}return sb.toString();}
- 分析得出:
- 如果属性名第一个字母是小写,第二个字母是大写(如
qTitle
),Jackson 会将整个属性名转为小写(qtitle
)。 - 这导致 JSON 里的
qTitle
和 Java 字段qTitle
匹配不上。
- 如果属性名第一个字母是小写,第二个字母是大写(如
解决方案
- 推荐:避免使用单字母+大写字母的属性名。
- 例如,将
qTitle
改为questionTitle
。
- 例如,将
- 如必须使用,添加
@JsonProperty
注解:@JsonProperty("qTitle") private String qTitle;
- 确保 Jackson 配置为默认大小写敏感,命名策略为
LOWER_CAMEL_CASE
。 - 团队命名规范建议:
- 尽量使用完整单词命名,避免单字母+大写字母的驼峰风格。
总结
本次 bug 的根本原因是 Jackson 对属性名的“遗留”处理逻辑,遇到小写字母后紧跟大写字母的属性名时,会将整个属性名转为小写,导致前后端字段无法正确映射。
建议统一命名规范,或使用 @JsonProperty
明确指定字段名,彻底规避此类问题。