Spring Boot枚举类型空字符串反序列化问题

【问题背景】

在基于Spring Boot的RESTful API应用中,前端需要传递一个带有枚举类型字段的JSON请求体。当用户未选择过滤条件时,前端传递了空字符串("")作为枚举参数值,导致后端API调用失败并返回HTTP 400错误。

这个问题可以前端处理,也可以后端处理,推荐后端处理,增加代码稳固性

需要知道的原理:Spring Boot默认使用Jackson作为其JSON处理库

Jackson在将JSON数据转换为Java对象时,遵循一个结构化的处理流程:

  1. 解析JSON文本:首先将JSON文本解析为令牌流 
  2. 确定目标类型:根据目标Java类型确定如何处理这些令牌
  3. 查找反序列化器:为每个字段查找合适的反序列化器 
  4. 执行反序列化:使用找到的反序列化器将JSON数据转换为Java对象

对于枚举类型,Jackson默认使用EnumDeserializer,它会尝试将JSON字符串值与枚举常量名进行精确匹配。

【错误信息与原因】

错误信息:
"Cannot deserialize value of type `XxxEnum` from String "": not one of the values accepted for Enum class: [EnumA,EnumB,EnumC]"

原因分析:
当Jackson(Spring Boot默认的JSON处理库)尝试将前端传来的空字符串("")转换为枚举类型时,由于空字符串不匹配任何已定义的枚举常量,Jackson抛出了InvalidFormatException异常。(此时还没有执行方法的代码,而是在处理参数,这个错误发生在HTTP请求处理的早期阶段 - 请求体反序列化过程中,甚至在进入控制器方法之前就已经失败。)

【解决方案】

方法:自定义枚举反序列化器

1. 在DTO类中添加注解:

public class QueryDTO {
    @JsonDeserialize(using = XxxEnumDeserializer.class)
    private XxxsEnum status;
    // 其他字段省略
}

2. 创建自定义反序列化器:
 

public class XxxEnumDeserializer extends JsonDeserializer<XxxEnum> {
    @Override
    public XxxEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String value = p.getValueAsString();
        if (value == null || value.isEmpty()) {
            return null;
        }
        return XxxEnum.valueOf(value);
    }
}

该反序列化器的核心逻辑是:当遇到空字符串时返回null,而不是尝试查找对应的枚举值。这样当查询条件中的status为null时,相应的查询条件不会被添加到SQL查询中,从而实现查询所有状态的数据。

自定义反序列化器会拦截Jackson的默认反序列化过程,采用自己的拦截过程

【总结】

相比修改前端代码,这种后端适应性处理也提高了系统的健壮性和用户体验。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值