在 jackson 的帮助下将 JSON 数组部分反序列化为 HashMap

Deserialize a JSON array partially into a HashMap with the help of jackson

我有以下 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>,如下所示:

{
  "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());

我是不是漏掉了什么?我希望有人能帮我解决这个问题。

也许您错过了添加 module.addDeserializer

HashMapValueDeserializer.class

public class HashMapValueDeserializer extends JsonDeserializer<HashMap<String, String>> {
    @Override
    public HashMap<String, String> deserialize(JsonParser parser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        HashMap<String, String> ret = new HashMap<String, String>();

        ObjectCodec codec = parser.getCodec();
        TreeNode node = codec.readTree(parser);

        for (JsonNode n : (ArrayNode)node){
            JsonNode c = n.get("c");
            JsonNode b = n.get("b");
            ret.put(c.asText(), b.asText());
        }
        return ret;
    }
}

Test.class

public class Test {
  public static void main(String[] args) throws FileNotFoundException, MalformedURLException, JsonProcessingException {
    String jsonArray = "[{ \"a\" : \"1\", \"b\" : \"2\", \"c\" : \"one\", \"d\" : \"3\" }, { \"a\" : \"4\", \"b\" : \"5\", \"c\" : \"two\", \"d\" : \"6\" }, { \"a\" : \"7\", \"b\" : \"8\", \"c\" : \"three\", \"d\" : \"9\" }]";

    ObjectMapper mapper = new ObjectMapper();

    SimpleModule module =
        new SimpleModule("HashMapValueDeserializer", new Version(1, 0, 0, null, null, null));
    module.addDeserializer(HashMap.class, new HashMapValueDeserializer());
    mapper.registerModule(module);

    HashMap<String, Integer> result = mapper.readValue(jsonArray, HashMap.class);
    System.out.println(result);
  }

}

输出:

{one=2, two=5, three=8}

无论如何,如果有人想在没有自定义反序列化器帮助的情况下这样做,可以分两步完成:将 JSON 数组转换为自定义对象列表,然后将该数组转换为映射在流的帮助下。请记住,此解决方案的性能落后于公认的答案。

ObjectMapper objectMapper = new ObjectMapper();
//converting the json to a list
List<CustomObject> list = Arrays.asList(objectMapper.readValue(json, CustomObject[].class));
//converting the list to a map
Map<String,Integer> map = list.stream().collect(Collectors.toMap(CustomObject::getString, CustomObject::getInteger));

//the custom object for the list (uses lombok for getters and setters)
@Getter
@Setter
public class CustomObject{

    @JsonProperty(value = "c")
    private String string;

    @JsonProperty(value = "b")
    private Integer integer;

}

然而,所有这些都可以在一行中完成:

Map<String,Integer> map = Arrays.stream(objectMapper.readValue(json, CustomObject[].class)).collect(Collectors.toMap(CustomObject::getString, CustomObject::getInteger));