Jackson-将对象的内部列表反序列化为更高级别的列表 [英] Jackson - deserialize inner list of objects to list of one higher level
问题描述
使用Spring Boot和Jackson,如何将包装好的/内部列表反序列化为直接在外部级别的列表?
With Spring Boot and Jackson, how can I deserialize a wrapped/inner list into a list directly in the outer level?
例如,我有:
{
"transaction": {
"items": {
"item": [
{
"itemNumber": "193487654",
"itemDescription": "Widget",
"itemPrice": "599.00",
"itemQuantity": "1",
"itemBrandName": "ACME",
"itemCategory": "Electronics",
"itemTax": "12.95"
},
{
"itemNumber": "193487654",
"itemDescription": "Widget",
"itemPrice": "599.00",
"itemQuantity": "1",
"itemBrandName": "ACME",
"itemCategory": "Electronics",
"itemTax": "12.95"
}
]
},
...
}
}
在JSON中,item
是items
下的列表;但是我想将其解析为直接在transaction
下的名为items
的列表,而不是定义包含名为item
的列表的DTO Items
.
In the JSON, item
is a list under items
; but I want to parse it as a list named items
, directly under transaction
, instead of defining a DTO Items
which contains a list named item
.
这可能吗?如何定义此DTO Item
?
Is this possible? How to define this DTO Item
?
public class TrasactionDTO {
private List<Item> items;
...
}
public class Item {
}
此问题类似,但不能解决问题. 使用杰克逊反序列化包装列表
This question is similar but does not solve the problem. Deserialize wrapped list using Jackson
推荐答案
我们需要实现自定义反序列化器.因为我们要跳过一个内部字段,所以我们的实现应该:
We need to implement custom deserialiser. Because we want to skip one inner field our implementation should:
-
{
-跳过起始对象 -
"any_field_name"
-跳过任何字段名称.我们假设只有一个内部字段. -
[{}, ..., {}]
-为List
使用默认的反序列化器. -
}
-跳过最终对象
{
- skip start object"any_field_name"
- skip any field name. We assume that we have only one inner field.[{}, ..., {}]
- use default deserialiser forList
.}
- skip end object
使用上述概念实现应该很容易:
Using above concept implementation should be easy:
public class InnerListDeserializer extends JsonDeserializer<List> implements ContextualDeserializer {
private final JavaType propertyType;
public InnerListDeserializer() {
this(null);
}
public InnerListDeserializer(JavaType propertyType) {
this.propertyType = propertyType;
}
@Override
public List deserialize(JsonParser p, DeserializationContext context) throws IOException {
p.nextToken(); // SKIP START_OBJECT
p.nextToken(); // SKIP any FIELD_NAME
List list = context.readValue(p, propertyType);
p.nextToken(); // SKIP END_OBJECT
return list;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext context, BeanProperty property) {
return new InnerListDeserializer(property.getType());
}
}
假设我们有这样的JSON
有效负载:
Let's assume we have JSON
payload like this:
{
"transaction": {
"items": {
"item": [
{
"itemNumber": "193487654",
"itemDescription": "Widget",
"itemPrice": "599.00",
"itemQuantity": "1",
"itemBrandName": "ACME",
"itemCategory": "Electronics",
"itemTax": "12.95"
},
{
"itemNumber": "193487654",
"itemDescription": "Widget",
"itemPrice": "599.00",
"itemQuantity": "1",
"itemBrandName": "ACME",
"itemCategory": "Electronics",
"itemTax": "12.95"
}
]
},
"name": "Pickle Rick"
}
}
在JSON
之上,我们可以映射到以下POJO
类:
Above JSON
we can map to below POJO
classes:
@JsonRootName("transaction")
public class Transaction {
private String name;
private List<Item> items;
@JsonDeserialize(using = InnerListDeserializer.class)
public List<Item> getItems() {
return items;
}
// getters, setters, toString
}
public class Item {
private String itemNumber;
// getters, setters, toString
}
为了展示它适用于许多不同的模型,让我们再介绍一个JSON
有效负载:
To show it works for many different models let's introduce one more JSON
payload:
{
"product": {
"products": {
"innerArray": [
{
"id": "1234"
}
]
}
}
}
和另外两个POJO
类:
@JsonRootName("product")
class Product {
private List<ProductItem> products;
@JsonDeserialize(using = InnerListDeserializer.class)
public List<ProductItem> getProducts() {
return products;
}
// getters, setters, toString
}
class ProductItem {
private String id;
// getters, setters, toString
}
现在我们可以测试我们的解决方案了:
Now we can test our solution:
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class JSoupTest {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
File jsonFile = new File("Path to 1-st JSON").getAbsoluteFile();
File jsonFile1 = new File("Path to 2-nd JSON").getAbsoluteFile();
System.out.println(mapper.readValue(jsonFile, Transaction.class));
System.out.println(mapper.readValue(jsonFile1, Product.class));
}
}
上面的示例打印:
Transaction{items=[Item{itemNumber=193487654}, Item{itemNumber=193487654}], name='Pickle Rick'}
Product{products=[ProductItem{id='1234'}]}
有关更多信息,请阅读:
For more info read:
- 自定义Jackson Deserializer可以访问当前字段类
- 杰克逊自定义反序列化入门
- 杰克逊异常–问题和解决方案
- Jackson UNWRAP_ROOT_VALUE
- 在Spring中配置ObjectMapper
- Custom Jackson Deserializer Getting Access to Current Field Class
- Getting Started with Custom Deserialization in Jackson
- Jackson Exceptions – Problems and Solutions
- Jackson UNWRAP_ROOT_VALUE
- Configuring ObjectMapper in Spring
这篇关于Jackson-将对象的内部列表反序列化为更高级别的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!