在 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));
我有以下 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));