【发布时间】:2021-10-31 13:25:11
【问题描述】:
我正在使用Jackson 对 JSON 进行 Deseilization。 Deseilization 非常适合带有 CustomerDocument 的 JSON。但是,我有一个新要求,我需要确定提供的 JSON 是否具有 CustomerDocument 或只有 Customer。
我能够为两者开发逻辑,但问题是当我尝试合并时它不适用于CustomerDocument。我正在寻找一种对两者都适用的解决方案。我想做的就是构建逻辑来区分基于customerDocument 和单个Customer 的传入JSON。
下面是CustomerDocument JSON:
{
"isA": "CustomerDocument",
"customerList": [
{
"isA": "Customer",
"name": "Batman",
"age": "2008"
}
]
}
客户类:
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Customer {
private String isA;
private String name;
private String age;
}
杰克逊主要:
public class JacksonMain {
public static void main(String[] args) throws IOException {
final InputStream jsonStream = JacksonMain.class.getClassLoader().getResourceAsStream("Customer.json");
final JsonParser jsonParser = new JsonFactory().createParser(jsonStream);
final ObjectMapper objectMapper = new ObjectMapper();
jsonParser.setCodec(objectMapper);
//Goto the start of the document
jsonParser.nextToken();
//Go until the customerList has been reached
while (!jsonParser.getText().equals("customerList")) {
jsonParser.nextToken();
}
jsonParser.nextToken();
//Loop through each object within the customerList and deserilize them
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
final JsonNode customerNode = jsonParser.readValueAsTree();
final String eventType = customerNode.get("isA").asText();
Object event = objectMapper.treeToValue(customerNode, Customer.class);
System.out.println(event.toString());
}
}
}
上面的代码完美运行并产生以下结果:
Customer(isA=Customer, name=Batman, age=2008)
场景 2
现在用户可以直接提供customer 对象,而无需customerDocument。像这样的:
{
"isA": "Customer",
"name": "Superman",
"age": "2013"
}
'Customer.class' 将保持不变,JacksonMain 将被修改为:
public class JacksonMain {
public static void main(String[] args) throws IOException {
final InputStream jsonStream = JacksonMain.class.getClassLoader().getResourceAsStream("Customer.json");
final JsonParser jsonParser = new JsonFactory().createParser(jsonStream);
final ObjectMapper objectMapper = new ObjectMapper();
jsonParser.setCodec(objectMapper);
//Goto the start of the document
jsonParser.nextToken();
final JsonNode jsonNode = jsonParser.readValueAsTree();
final String inputType = jsonNode.get("isA").asText();
if (inputType.equalsIgnoreCase("Customer")) {
Object singleCustomer = objectMapper.treeToValue(jsonNode, Customer.class);
System.out.println(singleCustomer.toString());
} else if (inputType.equalsIgnoreCase("CustomerDocument")) {
//Go until the customerList has been reached
while (!jsonParser.getText().equals("customerList")) {
jsonParser.nextToken();
}
jsonParser.nextToken();
//Loop through each object within the customerList and deserilize them
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
final JsonNode customerNode = jsonParser.readValueAsTree();
final String eventType = customerNode.get("isA").asText();
Object event = objectMapper.treeToValue(customerNode, Customer.class);
System.out.println(event.toString());
}
}
}
}
对于单个CUstomer,这将产生以下结果:
Customer(isA=Customer, name=Superman, age=2013)
现在,如果我提供CustomerDocument(第一个 JSON),那么对于相同的代码,它将无法工作并且会因错误而失败:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "com.fasterxml.jackson.core.JsonParser.getText()" is null
at stackover.JacksonMain.main(JacksonMain.java:32)
我知道这个问题是因为这条线而发生的
final JsonNode jsonNode = jsonParser.readValueAsTree();
有人可以解释一下如何使用 Jackson 使代码同时适用于 JSON customerDocument 和单个 Customer 类型吗?我只想区分传入的 JSON 是 customerDocument 还是单个 Customer。任何帮助将不胜感激。
- 我想使用 Jackson 来区分两种输入。
- 如果不需要创建任何
additional classes,那就太好了。但是,如果需要创建interface来实现此目的,也可以。 - 我的
CustomerList可能非常大,所以我一页一页地阅读,所以它不会占用太多内存。因此我没有CustomerDocument和List<Customer>的类,而是我正在查看它并一一映射。
【问题讨论】:
标签: java jackson json-deserialization jackson-databind jackson2