Java中將 Jackson JsonNode 轉換為型別化集合

banq發表於2024-05-09

在本教程中,我們將探索將 Jackson 的原始資料型別JsonNode轉換為型別化 Java 集合的不同方法 。雖然我們可以使用JsonNode本身讀取 JSON  ,但將其轉換為 Java 集合可能會很有幫助。 Java 集合提供了優於原始 JSON 資料的優勢,例如型別安全、更快的處理以及更多特定於型別的操作的可用性。

設定示例
在我們的程式碼示例中,我們將瞭解將 JsonNode轉換 為 物件列表 或 對映 的不同方法。讓我們設定示例的構建塊。

依賴性
首先,我們將 Jackson Core依賴項新增到pom.xml檔案中:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.17.0</version>
</dependency>

JSON資料
接下來,讓我們為我們的用例定義一個 JSON:

{
    <font>"persons": [
        {
           
"name": "John",
           
"age": 30
        },
        {
           
"name": "Alice",
           
"age": 25
        }
    ],
   
"idToPerson" : {
       
"1234": {
           
"name": "John",
           
"age": 30
        },
       
"1235": {
           
"name": "Alice",
           
"age": 25
        }
    }
}

在上面的 JSON 中,我們有一個 JSON 陣列people 和一個 JSON 物件 idToPerson。我們將研究將它們轉換為 Java 集合的方法。

資料傳輸物件
讓我們定義一個  可以在示例中使用的Person類:

public class Person {
    private String name;
    private int age;
    
    <font>// constructors/getters/setters<i>
}

將 JSON 字串轉換為JsonNode
如果我們想從整個 JSON 中讀取一個物件,我們可以使用 Jackson 的ObjectMapper 類來實現:

JsonNode rootNode = new ObjectMapper().readTree(jsonString);
JsonNode childNode = rootNode.get(<font>"persons");

要將整個 JSON 轉換為 JsonNode 物件,我們使用 readTree() 方法。然後,我們  使用 get()方法遍歷JsonNode物件,該方法返回具有指定名稱的巢狀物件。

手動轉換
在檢查庫方法之前,我們先看一下手動將 JsonNode轉換 為集合的方法。

手動將JsonNode轉換為列表
要將JsonNode轉換為列表,我們可以逐項遍歷它並用它建立一個List物件:

List<Person> manualJsonNodeToList(JsonNode personsNode) {
    List<Person> people = new ArrayList<>();
    for (JsonNode node : personsNode) {
        Person person = new Person(node.get(<font>"name").asText(), node.get("age").asInt());
        people.add(person);
    }
    return people;
}

在這裡,我們使用迴圈來遍歷輸入節點的所有子節點。僅當我們的輸入節點是陣列時,這才有可能。

對於每個節點,我們建立一個 Person物件並將其新增到列表中。我們使用get(fieldName)方法從節點 獲取姓名和年齡 。  JsonNode 提供了各種方法將返回值轉換為原始 Java 型別。這裡,  asText() 和 asInt()方法 分別 將值轉換為 String 和 int 。

手動將JsonNode轉換為Map
讓我們看一下地圖的類似轉換:

Map<String, Person> manualJsonNodeToMap(JsonNode idToPersonsNode) {
    Map<String, Person> mapOfIdToPerson = new HashMap<>();
    idToPersonsNode.fields()
      .forEachRemaining(node -> mapOfIdToPerson.put(node.getKey(),
        new Person(node.getValue().get(<font>"name").asText(), node.getValue().get("age").asInt())));
    return mapOfIdToPerson;
}

在這裡,我們使用fields()方法來迭代對映條目。它返回一個 Iterator<Map.Entry<String, JsonNode>>物件,我們可以進一步處理它。接下來,我們讀取每個條目並將其放入Map中。

使用Jackson的readValue()和convertValue()
Jackson提供了多種方法將 JsonNode轉換為Java物件。讓我們看一下其中的兩個。

1.使用readValue()
readValue  () 方法可用於  使用 TypeReference轉換為List 或 Map:

List<Person> readValueJsonNodeToList(JsonNode personsNode) throws IOException {
    TypeReference<List<Person>> typeReferenceList = new TypeReference<List<Person>>() {};
    return new ObjectMapper().readValue(personsNode.traverse(), typeReferenceList);
}
Map<String, Person> readValueJsonNodeToMap(JsonNode idToPersonsNode) throws IOException {
    TypeReference<Map<String, Person>> typeReferenceMap = new TypeReference<Map<String, Person>>() {};
    return new ObjectMapper().readValue(idToPersonsNode.traverse(), typeReferenceMap);
}

首先,我們 透過傳遞需要轉換的確切型別來建立一個TypeReference物件。然後我們呼叫 readValue() 方法,其中 JsonParser由jsonNode.traverse() 提供 。使用解析器,它根據我們提供的TypeReference將節點反序列化為列表或對映 。

2.使用convertValue()
類似地,我們可以使用 convertValue() 方法:

List<Person> convertValueJsonNodeToList(JsonNode personsNode) {
    TypeReference<List<Person>> typeReferenceList = new TypeReference<List<Person>>() {};
    return new ObjectMapper().convertValue(personsNode, typeReferenceList);
}
Map<String, Person> convertValueJsonNodeToMap(JsonNode idToPersonsNode) {
    TypeReference<Map<String, Person>> typeReferenceMap = new TypeReference<Map<String, Person>>() {};
    return new ObjectMapper().convertValue(idToPersonsNode, typeReferenceMap);
}

ConvertValue  ()方法的工作原理是首先序列化輸入物件,然後將其反序列化為所需的型別。 因此,它可以更靈活地用於從一個物件轉換為另一個物件。例如,我們還可以使用它來從 Java 物件到 JsonNode進行反向比較。

自定義解串器
我們還可以提供自定義解串器來執行轉換。讓我們看看如何定義一個:

public class CustomPersonListDeserializer extends JsonDeserializer<List<Person>> {
    @Override
    public List<Person> deserialize(com.fasterxml.jackson.core.JsonParser p, 
      com.fasterxml.jackson.databind.DeserializationContext ctxt) throws IOException {
        ObjectMapper objectMapper = (ObjectMapper) p.getCodec();
        List<Person> personList = new ArrayList<>();
        JsonNode personsNode = objectMapper.readTree(p);
        for (JsonNode node : personsNode) {
            personList.add(objectMapper.readValue(node.traverse(), Person.class));
        }
        return personList;
    }
}

讓我們看一下程式碼中的幾個重要部分:
  • 首先,該類擴充套件了 Jackson 的JsonDeserializer。
  • 然後,我們重寫deserialize()方法並提供我們的實現。
  • 在實現中,我們  從 JsonParser物件中獲取ObjectMapper  。
  • objectMapper.readTree() 將解析器表示的整個樹轉換為 JsonNode 例項。
  • 最後,與手動轉換類似,我們 透過迴圈節點將 JSON 陣列中的每個節點轉換為Person物件。

解串器的工作方式與其他方法類似,只是它可以提供關注點分離。此外,自定義反序列化器提供了靈活性,因為我們可以在呼叫程式碼中輕鬆地在反序列化器之間切換。

相關文章