如何在Jackson中解开嵌套包裹的列表?无需额外Bean实现
解决GraphQL风格edges/node嵌套的JSON反序列化问题(无需额外Bean)
嘿,这个GraphQL风格的edges/node嵌套结构确实挺让人头疼的,不过不用额外定义中间Bean也能轻松搞定反序列化!我来给你说说具体怎么做,假设你用的是Java里最常用的Jackson序列化库:
核心思路
你的JSON里images字段是一个包含edges数组的对象,每个edges元素里的node才是真正的Image对象。我们需要自定义一个反序列化器,把这种嵌套结构“展平”成Set<Image>类型,直接适配你现有的Product类。
步骤1:编写自定义反序列化器
针对Set<Image>类型写一个反序列化器,解析edges数组并提取每个node里的Image对象:
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.HashSet; import java.util.Set; public class ImageSetDeserializer extends JsonDeserializer<Set<Image>> { @Override public Set<Image> deserialize(JsonParser parser, DeserializationContext context) throws IOException { // 读取整个images节点的JSON树 JsonNode rootNode = parser.getCodec().readTree(parser); // 获取edges数组节点 JsonNode edgesNode = rootNode.get("edges"); Set<Image> images = new HashSet<>(); if (edgesNode != null && edgesNode.isArray()) { // 遍历每个edge节点,提取node里的Image对象 for (JsonNode edgeNode : edgesNode) { JsonNode nodeNode = edgeNode.get("node"); if (nodeNode != null) { // 将node节点转换成Image对象 Image image = parser.getCodec().treeToValue(nodeNode, Image.class); images.add(image); } } } return images; } }
步骤2:在Product类上添加注解
在Product类的images字段上添加@JsonDeserialize注解,指定使用我们刚才写的反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.util.Set; public class Product { public String id; public String vendor; // 指定用自定义反序列化器处理这个字段 @JsonDeserialize(using = ImageSetDeserializer.class) public Set<Image> images; } public class Image { public String originalSrc; }
这样Jackson在反序列化的时候,就会自动用这个自定义逻辑把嵌套的edges/node结构转换成Set<Image>,完全不需要额外的中间Bean!
进阶:通用化反序列化器(支持多种类型)
如果你的项目里有很多类似的edges/node嵌套数组,可以写一个通用泛型反序列化器,避免重复代码:
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.HashSet; import java.util.Set; public class EdgesNodeSetDeserializer<T> extends JsonDeserializer<Set<T>> { private final Class<T> targetType; // 构造函数传入目标类型 public EdgesNodeSetDeserializer(Class<T> targetType) { this.targetType = targetType; } @Override public Set<T> deserialize(JsonParser parser, DeserializationContext context) throws IOException { JsonNode rootNode = parser.getCodec().readTree(parser); JsonNode edgesNode = rootNode.get("edges"); Set<T> items = new HashSet<>(); if (edgesNode != null && edgesNode.isArray()) { for (JsonNode edgeNode : edgesNode) { JsonNode nodeNode = edgeNode.get("node"); if (nodeNode != null) { T item = parser.getCodec().treeToValue(nodeNode, targetType); items.add(item); } } } return items; } }
然后针对Image类型写一个子类(因为Java注解不支持直接传递泛型参数):
public class ImageEdgesSetDeserializer extends EdgesNodeSetDeserializer<Image> { public ImageEdgesSetDeserializer() { super(Image.class); } }
最后在Product的images字段上用这个子类即可:
@JsonDeserialize(using = ImageEdgesSetDeserializer.class) public Set<Image> images;
这样以后遇到其他类似的嵌套结构,只需要写一个对应的子类就能复用逻辑啦!
内容的提问来源于stack exchange,提问作者Mridang Agarwalla
相关产品推荐
相关产品推荐

