如何使用Jackson将对象数组反序列化为以对象属性为键的Map
嗨,这个需求我之前也碰到过,Jackson完全能搞定,给你两种实用的方案:
方案一:自定义Json反序列化器
这种方式灵活性最高,适合后续可能有扩展需求的场景:
- 首先定义你的
Symbol实体类:
public class Symbol { private String a; private String b; // 生成无参构造器、全参构造器、getter和setter方法 }
- 编写自定义的反序列化器,负责把JSON数组转成以
a属性为键的Map:
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.HashMap; import java.util.Iterator; import java.util.Map; public class SymbolArrayToMapDeserializer extends JsonDeserializer<Map<String, Symbol>> { @Override public Map<String, Symbol> deserialize(JsonParser parser, DeserializationContext context) throws IOException { Map<String, Symbol> symbolMap = new HashMap<>(); // 读取JSON数组节点 JsonNode arrayNode = parser.getCodec().readTree(parser); Iterator<JsonNode> elementIterator = arrayNode.elements(); while (elementIterator.hasNext()) { // 把每个数组元素转成Symbol对象 Symbol symbol = parser.getCodec().treeToValue(elementIterator.next(), Symbol.class); // 以a属性为键存入Map symbolMap.put(symbol.getA(), symbol); } return symbolMap; } }
- 在
MyContainer的symbols字段上标注使用这个反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.util.Map; public class MyContainer { private String name; @JsonDeserialize(using = SymbolArrayToMapDeserializer.class) private Map<String, Symbol> symbols; // 生成无参构造器、getter和setter方法 }
方案二:利用@JsonCreator工厂方法
这种方式更简洁,不需要额外写反序列化器类,适合简单场景:
直接修改MyContainer类,通过@JsonCreator标注的构造器来处理数组转Map的逻辑:
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Map; import java.util.Arrays; import java.util.stream.Collectors; public class MyContainer { private String name; private Map<String, Symbol> symbols; // 用@JsonCreator指定Jackson使用这个构造器反序列化 @JsonCreator public MyContainer( @JsonProperty("name") String name, @JsonProperty("symbols") Symbol[] symbolsArray ) { this.name = name; // 把数组转成Map,a属性作为键 this.symbols = Arrays.stream(symbolsArray) .collect(Collectors.toMap(Symbol::getA, symbol -> symbol)); } // 记得添加无参构造器(如果Jackson需要做序列化操作的话) public MyContainer() {} // 生成getter和setter方法 }
注意事项
- 你已经保证所有Symbol的
a属性值唯一,所以Collectors.toMap不会抛出DuplicateKeyException;如果后续有重复风险,可以添加第三个参数处理冲突,比如Collectors.toMap(Symbol::getA, symbol -> symbol, (oldVal, newVal) -> oldVal) - 两种方案都需要确保Jackson能正常反序列化
Symbol类,所以类要有无参构造器,或者用全参构造器配合@JsonProperty标注
内容的提问来源于stack exchange,提问作者Edy Bourne
相关产品推荐
相关产品推荐

