Spring Boot中枚举列表自定义反序列化报错排查
问题解决:Month枚举多格式反序列化报错处理
问题根源
你当前的CustomEnumDeserializer默认把输入当成JSON对象处理,强行读取lowerName和code字段,但实际请求里的period元素是数字或字符串(比如1、"january"),此时JsonNode不是对象,调用node.get("lowerName")会返回null,再调用asText()就触发空指针,导致解析错误。
修复后的反序列化器
修改CustomEnumDeserializer,让它支持数字、字符串、对象三种输入格式,同时对无效参数抛出明确错误:
public class CustomEnumDeserializer extends StdDeserializer<Month> { public CustomEnumDeserializer() { super(Month.class); } @Override public Month deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode node = jsonParser.getCodec().readTree(jsonParser); Month matchedMonth = null; // 处理数字格式(如1、2) if (node.isInt()) { int code = node.asInt(); matchedMonth = findByCode(code); } // 处理字符串格式(如"january"、"FEBRUARY") else if (node.isTextual()) { String name = node.asText(); matchedMonth = findByName(name); } // 处理对象格式(如{"code":1,"lowerName":"January"}) else if (node.isObject()) { String lowerName = node.has("lowerName") ? node.get("lowerName").asText() : null; int code = node.has("code") ? node.get("code").asInt() : -1; if (lowerName != null) { matchedMonth = findByName(lowerName); } if (matchedMonth == null && code != -1) { matchedMonth = findByCode(code); } } // 无匹配时抛出错误,Spring会自动返回400请求错误 if (matchedMonth == null) { throw new InvalidFormatException(jsonParser, "无效的月份参数:" + node.asText(), node.asText(), Month.class); } return matchedMonth; } // 根据code查找枚举 private Month findByCode(int code) { for (Month month : Month.values()) { if (month.getCode() == code) { return month; } } return null; } // 根据名称(忽略大小写)查找枚举 private Month findByName(String name) { for (Month month : Month.values()) { if (month.getLowerName().equalsIgnoreCase(name)) { return month; } } return null; } }
关键改动说明
- 类型判断:先检查
JsonNode的类型,分别处理数字、字符串、对象三种输入场景,避免无效的字段读取 - 空安全处理:读取对象字段前先判断
node.has("lowerName"),防止空指针 - 错误抛出:找不到匹配时抛出
InvalidFormatException,替代原来的返回null,Spring会自动生成标准化的错误响应,包含无效参数提示 - 代码拆分:把查找逻辑抽成单独方法,提高可读性
测试验证
现在三种输入格式都能正常解析:
- 数字列表:
{ "period": [1, 2, 3] }
- 字符串列表(大小写任意):
{ "period": ["january", "FEBRUARY", "March"] }
- 混合格式:
{ "period": ["january", 2, "March"] }
输入无效参数(如13、"invalidMonth")时,会返回标准化的400错误响应,包含具体的无效参数提示。
内容的提问来源于stack exchange,提问作者Gianni Spear
相关产品推荐
相关产品推荐

