如何借助Jackson将JSON数组部分反序列化为HashMap<String,Integer>
问题描述
我有如下JSON数组:
[ { "a": 1, "b": 2, "c": "one", "d": 3 }, { "a": 4, "b": 5, "c": "two", "d": 6 }, { "a": 7, "b": 8, "c": "three", "d": 9 } ]
我需要借助Jackson将其转换为HashMap<String,Integer>类型,最终结构如下,其中键为每个元素的"c"字段值,值为对应元素的"b"字段值:
{ "one": 2, "two": 5, "three": 8 }
我尝试过使用自定义反序列化器实现该需求,但无法正确注册,也不确定该实现方式是否正确。另外我拿到的JSON是直接的字符串格式,没有外层嵌套包装对象,因此无法使用@JsonDeserialize(using = CustomDeserializer.class)这类注解指定反序列化器。
因此我尝试直接在ObjectMapper中注册自定义反序列化器,使用了如下配置,但配置没有生效:
ObjectMapper objectMapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addDeserializer(new TypeReference<HashMap<String,Integer>>(){}, new CustomDeserializer());
请问我哪里配置有误?希望能得到解决方案。
解决方案
配置错误原因
你调用SimpleModule#addDeserializer时入参不符合要求,该方法第一个参数需要传入反序列化目标的Class对象,你传入的TypeReference不会被识别,因此注册的自定义反序列化器无法匹配到对应反序列化场景,自然不生效。
可选实现方案
方案1:无需自定义反序列化器(更简单,推荐)
先将JSON数组反序列化为中间结构,再手动提取字段生成目标Map,代码逻辑清晰且不会影响全局ObjectMapper的行为:
ObjectMapper objectMapper = new ObjectMapper(); // 先解析为JsonNode数组 JsonNode arrayNode = objectMapper.readTree(jsonStr); HashMap<String, Integer> result = new HashMap<>(); for (JsonNode item : arrayNode) { result.put(item.get("c").asText(), item.get("b").asInt()); }
你也可以定义简单实体类承接数组元素,通过流处理转换:
// 定义数组元素对应的实体类 @Data public class Element { private String c; private Integer b; // 未声明的a、d字段Jackson会自动忽略 } // 转换逻辑 List<Element> elementList = objectMapper.readValue(jsonStr, new TypeReference<List<Element>>() {}); HashMap<String, Integer> result = elementList.stream() .collect(Collectors.toMap(Element::getC, Element::getB, (oldVal, newVal) -> oldVal, HashMap::new));
方案2:正确注册自定义反序列化器
如果需要直接通过反序列化得到目标Map,可以按如下方式调整代码:
- 实现自定义反序列化器
public class CustomMapDeserializer extends StdDeserializer<HashMap<String, Integer>> { public CustomMapDeserializer() { super(HashMap.class); } @Override public HashMap<String, Integer> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { HashMap<String, Integer> result = new HashMap<>(); JsonNode arrayNode = p.getCodec().readTree(p); for (JsonNode item : arrayNode) { result.put(item.get("c").asText(), item.get("b").asInt()); } return result; } }
- 注册反序列化器并使用
ObjectMapper objectMapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); // 第一个参数传入HashMap的Class对象 simpleModule.addDeserializer(HashMap.class, new CustomMapDeserializer()); objectMapper.registerModule(simpleModule); // 直接反序列化得到目标Map HashMap<String, Integer> result = objectMapper.readValue(jsonStr, new TypeReference<HashMap<String, Integer>>() {});
注意:该方案会全局修改该ObjectMapper实例对HashMap类型的反序列化逻辑,如果你有其他正常反序列化HashMap的需求,不推荐使用该方案。
内容的提问来源于stack exchange,提问作者Martin Nöbel
相关产品推荐
相关产品推荐

