知識庫 / JSON / Jackson RSS 訂閱

Jackson 自定義反序列化入門指南

Data,Jackson
HongKong
6
10:03 PM · Dec 05 ,2025

1. 概述

本快速教程將演示如何使用 Jackson 2 通過自定義的 解器來反序列化 JSON。

要深入瞭解 Jackson 2 可以做的事情,請訪問主 Jackson 教程。

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 org.baeldung.jackson.dtos.Item), 
not marked as ignorable (3 known properties: "id", "owner", "itemName"])
 at [Source: java.io.StringReader@53c7a917; line: 1, column: 43] 
 (through reference chain: org.baeldung.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));
    }
}

如我們所見,反序列器正在使用標準的 Jackson 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 進行配置的情況下非常有用。

5. 為泛型類型創建自定義反序列器

現在,讓我們創建一個 Wrapper 類,其中包含泛型類型 T 的唯一參數:

public class Wrapper<T> {

    T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

我們的 ItemUser 屬性現在將改為 Wrapper<User> 類型:

public class Item {
    public int id;
    public String itemName;
    public Wrapper<User> owner;
}

讓我們為這個案例實現一個自定義的反序列化器。

首先,我們需要實現ContextualDeserializer接口,以便在Wrapper中獲取實體類型。我們將通過重寫createContextual()方法來實現。當該方法被調用時,上下文將被解析,並且可以通過BeanProperty參數檢索Wrapper的內容。

我們還需要擴展JsonDeserializer。因此,我們可以設置Wrapper值的具體類型在deserialize()方法中:

public class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer {

    private JavaType type;

    public WrapperDeserializer() {
        // Default constructor
    }

    private WrapperDeserializer(JavaType type) {
        this.type = type;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        JavaType wrapperType = property.getType().containedType(0);
        return new WrapperDeserializer(wrapperType);
    }

    @Override
    public Wrapper<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        Wrapper<?> wrapper = new Wrapper<>();
        wrapper.setValue(deserializationContext.readValue(jsonParser, type));
        return wrapper;
    }
}

這段 JSON 解析器還可以處理同一類中具有不同類型的多個 Wrapper 屬性。 假設我們有一個包含 Wrapper 及其多種類型的類:

public class ItemWithMultipleWrappers {
    private int id;
    private String itemName;
    private Wrapper<User> owner;
    private Wrapper<Integer> count;
}

在這種情況下,反序列化仍然有效,因為 createContextual() 方法會創建並返回一個具有正確類型的 WrapperDeserializer 實例,而不是直接設置類型字段。

最後,我們需要註冊自定義的序列化器,以便能夠對 JSON 進行反序列化。

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Wrapper.class, new WrapperDeserializer());
mapper.registerModule(module);

Item readValue = mapper.readValue(json, Item.class);

6. 結論

本文介紹瞭如何利用 Jackson 2 來讀取非標準 JSON 輸入,以及如何將該輸入映射到任何 Java 實體圖,並對映射過程擁有完全控制權。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.