如何使用 Java 的 Jackson 库将嵌套的 JSON 数组反序列化为 Map?
How to deserialize nested JSON array into a Map using Java's Jackson library?
我有这样的结构:
{
"name": "user",
"values":[["0.00207760","18.48000000"],["0.00207740","40.00000000"],["0.00207710","2.26000000"]]
}
我想像这样使用流行的 Jackson 库反序列化为 class:
public class Values {
public String name;
public Map<BigDecimal, BigDecimal> values = new HashMap<>();
}
其中 values
属性 中的每个条目都成为 class 映射中的 key/value 条目。
但是,如果我尝试使用 Jackson 进行简单的反序列化,则会出现此错误:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.TreeMap<java.lang.Object,java.lang.Object>` out of START_ARRAY token
at [Source: (String)"{"name": "user","values":[["0.00207760","18.48000000"],["0.00207740","40.00000000"],["0.00207710","2.26000000"]]...
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1442)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1216)
...
如何使用 Jackson 完成此操作?
谢谢!
爱德华多
你期望 Map
在 JSON
一侧由 JSON Object
表示,但有一个 JSON Array
可以默认映射到 List
, Set
或 array
。我建议在 POJO
中使用 List<List<BigDecimal>>
并创建一个将数据转换为 Map
:
的方法
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import java.io.File;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = JsonMapper.builder().build();
Values values = mapper.readValue(jsonFile, Values.class);
System.out.println(values.getValuesAsMap());
}
}
class Values {
private String name;
private List<List<BigDecimal>> values;
public Map<BigDecimal, BigDecimal> getValuesAsMap() {
return values.stream().collect(Collectors.toMap(
k -> k.get(0),
v -> v.get(1),
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new));
}
// getters, setters, toString
}
以上代码打印:
{0.00207760=18.48000000, 0.00207740=40.00000000, 0.00207710=2.26000000}
在其他情况下,您需要为 Map
实现一个 custom
反序列化器,并使用 @JsonDeserialize 注释为该字段注册它。
List 在内部数组中使用相同的数据类型。然而,我得到了一张地图,该地图被转换为嵌套的 jsonArray,其值为 jsonObject.
JSON:
{
"history": [
[
2,
{
"trx_id": "4014ae64ae9c45861ed4f0af30224b6741dcbb46",
...
"operation_id": 0
}
],
[
3,
{
"trx_id": "a4023a3641ffc112324427523945f641d88c5eae",
...
"operation_id": 0
}
]
]
}
3 class 答案:
public class HistoryListResponse {
private List<HistoryMapEntryResponse> history;
}
2ed class:
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonPropertyOrder({ "key", "trx"})
public class HistoryMapEntryResponse {
private int key;
private HistoryTrxResponse trx;
}
然后恢复正常json:
public class HistoryTrxResponse {
private String trx_id;
...
private int operation_id;
}
仍然需要一种方法将列表转换回 Map,但它非常接近,并且内部数据得到 parsed/deserialized。
我有这样的结构:
{
"name": "user",
"values":[["0.00207760","18.48000000"],["0.00207740","40.00000000"],["0.00207710","2.26000000"]]
}
我想像这样使用流行的 Jackson 库反序列化为 class:
public class Values {
public String name;
public Map<BigDecimal, BigDecimal> values = new HashMap<>();
}
其中 values
属性 中的每个条目都成为 class 映射中的 key/value 条目。
但是,如果我尝试使用 Jackson 进行简单的反序列化,则会出现此错误:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.TreeMap<java.lang.Object,java.lang.Object>` out of START_ARRAY token
at [Source: (String)"{"name": "user","values":[["0.00207760","18.48000000"],["0.00207740","40.00000000"],["0.00207710","2.26000000"]]...
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1442)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1216)
...
如何使用 Jackson 完成此操作?
谢谢!
爱德华多
你期望 Map
在 JSON
一侧由 JSON Object
表示,但有一个 JSON Array
可以默认映射到 List
, Set
或 array
。我建议在 POJO
中使用 List<List<BigDecimal>>
并创建一个将数据转换为 Map
:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import java.io.File;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = JsonMapper.builder().build();
Values values = mapper.readValue(jsonFile, Values.class);
System.out.println(values.getValuesAsMap());
}
}
class Values {
private String name;
private List<List<BigDecimal>> values;
public Map<BigDecimal, BigDecimal> getValuesAsMap() {
return values.stream().collect(Collectors.toMap(
k -> k.get(0),
v -> v.get(1),
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new));
}
// getters, setters, toString
}
以上代码打印:
{0.00207760=18.48000000, 0.00207740=40.00000000, 0.00207710=2.26000000}
在其他情况下,您需要为 Map
实现一个 custom
反序列化器,并使用 @JsonDeserialize 注释为该字段注册它。
List 在内部数组中使用相同的数据类型。然而,我得到了一张地图,该地图被转换为嵌套的 jsonArray,其值为 jsonObject.
JSON:
{
"history": [
[
2,
{
"trx_id": "4014ae64ae9c45861ed4f0af30224b6741dcbb46",
...
"operation_id": 0
}
],
[
3,
{
"trx_id": "a4023a3641ffc112324427523945f641d88c5eae",
...
"operation_id": 0
}
]
]
}
3 class 答案:
public class HistoryListResponse {
private List<HistoryMapEntryResponse> history;
}
2ed class:
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonPropertyOrder({ "key", "trx"})
public class HistoryMapEntryResponse {
private int key;
private HistoryTrxResponse trx;
}
然后恢复正常json:
public class HistoryTrxResponse {
private String trx_id;
...
private int operation_id;
}
仍然需要一种方法将列表转换回 Map,但它非常接近,并且内部数据得到 parsed/deserialized。