Contents

Jackson自定义反序列化

1. 概述

本快速教程将说明如何使用 Jackson 2 使用自定义反序列化器反序列化 JSON。

2.标准反序列化

让我们从定义两个实体开始,看看 Jackson 如何在没有任何自定义的情况下将 JSON 表示反序列化为这些实体:

public class User {
    public int id;
    public String name;
}
public class Item {
    public int id;
    public String itemName;
    public User owner;
}

现在让我们定义我们想要反序列化的 JSON 表示:

{
    "id": 1,
    "itemName": "theItem",
    "owner": {
        "id": 2,
        "name": "theUser"
    }
}

最后,让我们将这个 JSON 解组为 Java 实体:

Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);

3. ObjectMapper上的自定义反序列化器

在前面的示例中,JSON 表示与 Java 实体完美匹配。 接下来,我们将简化 JSON:

{
    "id": 1,
    "itemName": "theItem",
    "createdBy": 2
}

默认情况下,将其解组到完全相同的实体时,这当然会失败:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: 
Unrecognized field "createdBy" (class com.blogdemo.jackson.dtos.Item), 
not marked as ignorable (3 known properties: "id", "owner", "itemName"])
 at [Source: [[email protected]](/cdn_cgi/l/email_protection); line: 1, column: 43] 
 (through reference chain: com.blogdemo.jackson.dtos.Item["createdBy"])

我们将通过使用自定义 Deserializer 进行我们自己的反序列化来解决这个问题:

public class ItemDeserializer extends StdDeserializer<Item> { 
    public ItemDeserializer() { 
        this(null); 
    } 
    public ItemDeserializer(Class<?> vc) { 
        super(vc); 
    }
    @Override
    public Item deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        int id = (Integer) ((IntNode) node.get("id")).numberValue();
        String itemName = node.get("itemName").asText();
        int userId = (Integer) ((IntNode) node.get("createdBy")).numberValue();
        return new Item(id, itemName, new User(userId, null));
    }
}

正如我们所看到的,反序列化器正在使用 JSON 的标准杰克逊表示 - JsonNode。一旦输入 JSON 表示为JsonNode,我们现在可以从中提取相关信息并构建我们自己的Item实体。

简单来说,我们需要注册这个自定义的反序列化器,并正常反序列化 JSON:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Item.class, new ItemDeserializer());
mapper.registerModule(module);
Item readValue = mapper.readValue(json, Item.class);

4. 类上的自定义反序列化器

或者,我们也可以直接在类上注册反序列化器

@JsonDeserialize(using = ItemDeserializer.class)
public class Item {
    ...
}

使用在类级别定义的反序列化器,无需在ObjectMapper上注册它- 默认映射器可以正常工作:

Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);

在我们可能无法直接访问要配置的原始ObjectMapper的情况下,这种类型的 per-class 配置非常有用。