Jackson映射嵌套的JSON对象
Jackson映射嵌套的JSON对象
1.概述
使用JSON时的一个典型案例是处理从一个模型到另一个模型的转换。例如,我们希望将复杂的、多层嵌套的JSON对象反序列化为更简单的数据模型,以便在其他实体中使用。
在本文中,我们将研究如何使用Jackson 将嵌套的JSON对象反序列化为简单的数据结构。Jackson提供了以三种不同的方式反序列化JSON:
-
使用_@JsonProperty_
-
使用_JsonNode_
-
使用自定义_JsonDeserializer_
2. 添加Maven依赖
将以下依赖添加到_pom.xml_中:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
我们可以在mvnrepository上找到最新版本的_jackson-databind_。
3. 构造JSON数据源
将以下JSON作为示例的数据源。注意,在构造结构时,我们进行了两层嵌套:
{
"id": "957c43f2-fa2e-42f9-bf75-6e3d5bb6960a",
"name": "手机",
"brand": {
"id": "9bcd817d-0141-42e6-8f04-e5aaab0980b6",
"name": "华为",
"owner": {
"id": "b21a80b1-0c09-4be3-9ebd-ea3653511c13",
"name": "华为技术有限公司"
}
}
}
4.简化的对象模型
现在,我们需要将上述嵌套的JSON数据序列化到Product对象中,分别将JSON字符串的第一个、第二个、第三个name映射到Product的name、brandName、ownerName字段上。
public class Product {
private String id;
private String name;
private String brandName;
private String ownerName;
// 省略 getters and setters
}
5.使用@JsonProperty映射
要映射嵌套的_brandName_属性,首先需要将嵌套的_brand_对象解析到_Map_中并获取_name_属性。然后要映射_ownerName_,需要将嵌套的_owner_对象解析到到_Map_中并获取_name_属性。
public class Product {
//...
@JsonProperty("brand")
private void unpackNested(Map<String, Object> brand) {
this.brandName = (String) brand.get("name");
Map<String, String> owner = (Map<String, String>) brand.get("owner");
this.ownerName = owner.get("name");
}
}
测试代码如下:
@Test //使用@JsonProperty注解反序列化嵌套JSON
public void usingAnnotations() throws IOException {
ObjectMapper mapper=new ObjectMapper();
Product product = mapper.readerFor(Product.class).readValue(SOURCE_JSON);
assertEquals(product.getName(), "手机");
assertEquals(product.getBrandName(), "华为");
assertEquals(product.getOwnerName(), "华为技术有限公司");
System.out.println(product);
}
输出结果:
Product{id='957c43f2-fa2e-42f9-bf75-6e3d5bb6960a', name='手机', brandName='华为', ownerName='华为技术有限公司'}
6.使用JsonNode映射
首先,我们使用ObjectMapper_对象的_readTree方法将JSON字符串转换为JsonNode对象,然后从JsonNode对象中获取所需要的值,测试代码如下:
@Test //使用JsonNode反序列化嵌套JSON
public void usingJsonNode() throws IOException {
ObjectMapper mapper=new ObjectMapper();
JsonNode productNode = mapper.readTree(SOURCE_JSON);
Product product = new Product();
product.setId(productNode.get("id").textValue());
product.setName(productNode.get("name").textValue());
product.setBrandName(productNode.get("brand").get("name").textValue());
product.setOwnerName(productNode.get("brand").get("owner")
.get("name").textValue());
assertEquals(product.getName(), "手机");
assertEquals(product.getBrandName(), "华为");
assertEquals(product.getOwnerName(), "华为技术有限公司");
}
7.自定义JsonDeserializer进行映射
从实现原理来看,使用自定义的_JsonDeserializer_映射嵌套数据结构与_JsonNode_方法相同。首先创建_JsonDeserializer:_
public class ProductDeserializer extends StdDeserializer<Product> {
public ProductDeserializer() {
this(null);
}
public ProductDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Product deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonNode productNode = jp.getCodec()
.readTree(jp);
Product product = new Product();
product.setId(productNode.get("id")
.textValue());
product.setName(productNode.get("name")
.textValue());
product.setBrandName(productNode.get("brand")
.get("name")
.textValue());
product.setOwnerName(productNode.get("brand")
.get("owner")
.get("name")
.textValue());
return product;
}
}
7.1 手动注册反序列化器
手动注册我们自定义的反序列化器,客户端代码必须将JsonDeserializer添加到一个模块中,然后将这个模块注册到ObjectMapper中,最后调用readValue:
@Test //自定义反序列化手动注册
public void deserializerManuallyRegistered() throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Product.class, new ProductDeserializer());
mapper.registerModule(module);
Product product = mapper.readValue(SOURCE_JSON, Product.class);
assertEquals(product.getName(), "手机");
assertEquals(product.getBrandName(), "华为");
assertEquals(product.getOwnerName(), "华为技术有限公司");
}
7.2 自动注册反序列化器
针对手动注册_JsonDeserializer_,Jackson提供了替代方案,我们可以直接在类上注册反序列化器:
@JsonDeserialize(using = ProductDeserializer.class)
public class Product {
private String id;
private String name;
private String brandName;
private String ownerName;
//......
}
使用这种方法,无需手动注册。测试代码如下:
@Test //自定义反序列化自动注册
public void deserializerAutoRegistered() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(SOURCE_JSON, Product.class);
assertEquals(product.getName(), "手机");
assertEquals(product.getBrandName(), "华为");
assertEquals(product.getOwnerName(), "华为技术有限公司");
}

浙公网安备 33010602011771号