1. 簡介
使用 Jackson 處理預定義的 JSON 數據結構非常簡單。然而,有時我們需要處理動態的 JSON 對象。
在本快速教程中,我們將學習多種將動態 JSON 對象映射到 Java 類的方法。
請注意,在所有測試用例中,我們假設擁有 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. 使用
之前的解決方案在對象僅包含動態屬性時是好的選擇。但是,有時我們會在單個JSON對象中混合使用。
例如,我們需要扁平化我們的產品表示:
{
"name": "Pear yPhone 72",
"category": "cellphone",
"displayAspectRatio": "97:3",
"audioConnector": "none"
}
我們可以將這種結構視為動態對象。然而,這意味着我們無法定義常見的屬性,我們必須動態地處理它們。
或者,我們可以使用 來標記一個用於處理附加未知屬性的方法。 這樣的方法應該接受兩個參數,屬性的名稱和值:
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
}
請注意,我們必須實例化 以避免。
由於我們存儲動態屬性到 中,我們可以以與之前相同的方式使用它:
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。