我们需要实现自定义解串器。因为我们想跳过一个内部字段,所以我们的实现应该:
-
{
- 跳过起始对象
-
"any_field_name"
- 跳过任何字段名称。我们假设我们只有一个内部场。
-
[{}, ..., {}]
- 使用默认解串器List
.
-
}
- 跳过结束对象
使用上述概念实现应该很容易:
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
有效负载如下:
{
"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"
}
}
Above JSON
我们可以映射到下面POJO
课程:
@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
有效负载:
{
"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
}
现在我们可以测试我们的解决方案:
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'}]}
欲了解更多信息,请阅读:
- 自定义 Jackson 解串器获取当前字段类的访问权限 https://stackoverflow.com/questions/8944086/custom-jackson-deserializer-getting-access-to-current-field-class
- Jackson 中的自定义反序列化入门 https://www.baeldung.com/jackson-deserialization
- 杰克逊例外——问题和解决方案 https://www.baeldung.com/jackson-exception
- 杰克逊 UNWRAP_ROOT_VALUE https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/DeserializationFeature.html#UNWRAP_ROOT_VALUE
- 在 Spring 中配置 ObjectMapper https://stackoverflow.com/questions/7854030/configuring-objectmapper-in-spring