用Jackson映射动态JSON对象
1.介绍
使用Jackson来使用预定义的JSON数据结构非常简单。 但是,有时需要处理具有未知属性的动态JSON对象。
2.使用JsonNode
假设要在网上商店中处理产品规格。 所有产品都有一些共同的属性,但是还有其他一些属性,取决于产品的类型。
例如,想知道手机显示屏的长宽比,但是此属性对于鞋子来说意义不大。
数据结构如下
{
"name": "Pear yPhone 72",
"category": "cellphone",
"details": {
"displayAspectRatio": "97:3",
"audioConnector": "none"
}
}
将动态属性存储在details对象中。
可以使用以下Java类来映射公共属性:
class Product {
String name;
String category;
// standard getters and setters
}
最重要的是,需要适当的表示形式来表示Details对象。 例如,com.fasterxml.jackson.databind.JsonNode可以处理动态字典。
要使用它,我们必须将其作为字段添加到我们的Product类中:
class Product {
String name;
String category;
JsonNode details;
// standard getters and setters
}
String json="{ \"name\": \"Pear yPhone 72\", \"category\": \"cellphone\", \"details\": { \"displayAspectRatio\": \"97:3\", \"audioConnector\": \"none\" }}";
ObjectMapper objectMapper = new ObjectMapper();
Product product = objectMapper.readValue(json, Product.class);
System.out.println(product);
//Product(name=Pear yPhone 72, category=cellphone, details={"displayAspectRatio":"97:3","audioConnector":"none"})
3.使用Map
可以通过将java.util.Map用于details字段来解决此问题。 更准确地说,我们必须使用Map <String,Object>。
其他所有内容都可以保持不变:
class Product {
String name;
String category;
Map<String, Object> details;
// standard getters and setters
}
执行如上代码输入结果如下
Product(name=Pear yPhone 72, category=cellphone, details={
displayAspectRatio=97:3, audioConnector=none})
4.使用@JsonAnySetter
当对象仅包含动态属性时,上述解决方案很好。 但是,有时我们在单个JSON对象中混合了固定属性和动态属性。
例如,可能需要展平我们的产品表示形式:
{
"name": "Pear yPhone 72",
"category": "cellphone",
"displayAspectRatio": "97:3",
"audioConnector": "none"
}
可以将这样的结构视为动态对象。 不幸的是,这意味着我们无法定义通用属性-我们也必须动态对待它们。
或者,我们可以使用@JsonAnySetter标记用于处理其他未知属性的方法。 这种方法应接受两个参数:属性的名称和值:
class Product {
Map<String, Object> details = new LinkedHashMap<>();
@JsonAnySetter
void setDetail(String key, Object value) {
details.put(key, value);
}
}
String json="{ \"name\": \"Pear yPhone 72\", \"category\": \"cellphone\", \"displayAspectRatio\": \"97:3\", \"audioConnector\": \"none\" }";
ObjectMapper objectMapper = new ObjectMapper();
Product product = objectMapper.readValue(json, Product.class);
System.out.println(product);
//Product(details={name=Pear yPhone 72, category=cellphone, displayAspectRatio=97:3, audioConnector=none})