解决一个JSON反序列化问题-空字符串变为空集合
1.问题场景
当我后端实体中定义如下:
private List<String> projectTypeId;
如果前端传projectTypeId 是 null 或者 [] 都是没问题的。当前端传"" 则会报错。 报错如下:
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") to element of `java.util.ArrayList<java.lang.String>` (but could if coercion was enabled using `CoercionConfig`)
at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 8, column: 22] (through reference chain: com.safesoft.web.landProject.vo.LandProjectQueryVO["projectTypeId"])
意思是无法将空字符串强转为集合
2.解决办法(前端)
前端把“” 变为null或者[]即可
(但是我所在这个项目,原先定义的是 private String projectTypeId; 前端传"" 也没毛病,但是后期更改需求,需要变成集合。但是前端每个人写的语法不一样,上个前端人员如果是null则传的"" 。因此造成这个bug)
3.解决办法(后端)
3.1 编写一个自定义 JSON 反序列化器 EmptyStringListDeserializer
package com.safesoft.common.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义 JSON 反序列化器,用于处理空字符串在 List 中的情况。
* 该反序列化器设计用于与 Java 类中的 `@JsonDeserialize` 注解一起使用,该注解放在 List<String> 字段上。
* @author Kevin.Wan
* @date 2023/12/15
**/
public class EmptyStringListDeserializer extends JsonDeserializer<List<String>> {
/**
* 反序列化 JSON 数组,处理空字符串并将其转换为空列表。
*
* @param p JSON 解析器。
* @param ctxt 反序列化上下文。
* @return 包含反序列化字符串的 List<String>。
* @throws IOException 如果在反序列化过程中发生 I/O 错误。
*/
@Override
public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// 读取整个 JSON 节点
JsonNode node = p.readValueAsTree();
// 检查节点是否为 null、缺失或不是数组
if (node == null || node.isNull() || node.isMissingNode() || !node.isArray()) {
// 对于 null、缺失或非数组情况,返回空列表
return new ArrayList<>();
} else {
// 处理数组中的每个元素
List<String> values = new ArrayList<>();
for (JsonNode element : node) {
// 检查元素是否为文本节点
if (element.isTextual()) {
// 将文本值添加到列表中
values.add(element.textValue());
}
}
// 返回反序列化字符串的列表
return values;
}
}
}
3.2 然后在可能存在空字符串转换集合的实体上 添加注解
/**
* 项目类型id
*/
@JsonDeserialize(using = EmptyStringListDeserializer.class)
private List<String> projectTypeId;
@JsonDeserialize
是在反序列化时,所以就是对参数进行封装,故到的是 setXxxx() 方法,所以需要将注解添加到对应的 set 方法上,若使用了 Lombok 需要自己定义相应的 set 方法。
需要使用 using 属性指定处理参数的类,该类需要继承 JsonDeserializer 类,并重写 deserialize()。
自己见解:
@JsonDeserialize是String提供的反序列化注解,其中 using可以自定义一个反序列化,EmptyStringListDeserializer则是我们自定义处理空字符串转换为空集合的反序列化器