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
明確指定字段名,徹底規避此類問題。