知識庫 / JSON / Jackson RSS 訂閱

使用 Jackson 動態映射動態 JSON 對象

Jackson
HongKong
6
09:53 PM · Dec 05 ,2025

1. 引言

使用 Jackson 處理預定義的 JSON 數據結構非常簡單。然而,有時我們需要處理動態的 JSON 對象,這些對象具有未知的屬性。

在本快速教程中,我們將學習多種將動態 JSON 對象映射到 Java 類的方法。

請注意,在所有測試中,我們假設我們擁有類型為 com.fasterxml.jackson.databind.ObjectMapper 的字段 objectMapper

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 {

    // common fields

    JsonNode details;

    // standard getters and setters
}

最後,我們驗證它是否有效:

String json = "<json object>";

Product product = objectMapper.readValue(json, Product.class);

assertThat(product.getName()).isEqualTo("Pear yPhone 72");
assertThat(product.getDetails().get("audioConnector").asText()).isEqualTo("none");

然而,這個解決方案存在問題:我們的類依賴於 Jackson 庫,因為我們有 JsonNode 字段。

3. 使用 Map

我們可以通過使用 java.util.Map 來解決這個問題,應用於 details 字段。更準確地説,我們需要使用 Map<String, Object>

其他部分可以保持不變:

class Product {

    // common fields

    Map<String, Object> details;

    // standard getters and setters
}

然後我們可以用一個測試來驗證它:

String json = "<json object>";

Product product = objectMapper.readValue(json, Product.class);

assertThat(product.getName()).isEqualTo("Pear yPhone 72");
assertThat(product.getDetails().get("audioConnector")).isEqualTo("none");

4. 使用 @JsonAnySetter

前述的解決方案在對象僅包含動態屬性時是良好的選擇。然而,有時我們會在單個 JSON 對象中混合使用固定和動態屬性

例如,我們可能需要扁平化我們的產品表示:

{
    "name": "Pear yPhone 72",
    "category": "cellphone",
    "displayAspectRatio": "97:3",
    "audioConnector": "none"
}

我們可以將這種結構視為一個動態對象。不幸的是,這意味着我們無法定義常見的屬性,而是必須動態地處理它們。

或者,我們可以使用 @JsonAnySetter 來標記一個用於處理額外的、未知的屬性的方法。 這樣的方法應該接受兩個參數:名稱和值。

class Product {

    // common fields

    Map<String, Object> details = new LinkedHashMap<>();

    @JsonAnySetter
    void setDetail(String key, Object value) {
        details.put(key, value);
    }

    // standard getters and setters
}

請注意,必須實例化 details 對象以避免 NullPointerException

由於我們使用 Map 存儲動態屬性,我們可以以之前的方式使用它:

String json = "<json object>";

Product product = objectMapper.readValue(json, Product.class);

assertThat(product.getName()).isEqualTo("Pear yPhone 72");
assertThat(product.getDetails().get("audioConnector")).isEqualTo("none");

5. 創建自定義反序列器

對於大多數情況,這些解決方案已經足夠好用;然而,有時我們需要更多的控制。例如,我們可以將 JSON 對象的反序列化信息存儲在數據庫中。

我們可以使用自定義反序列器來處理這些情況。由於這是一個更復雜的主題,因此我們在另一篇文章中進行了詳細説明,即《Jackson 自定義反序列化入門》。

6. 結論

在本文中,我們探討了多種處理動態 JSON 對象的方法,這些方法使用了 Jackson。

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

發佈 評論

Some HTML is okay.