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(), "华为技术有限公司");
}
posted @ 2023-01-30 16:36  明小子@  阅读(6)  评论(0)    收藏  举报