添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在本教程中,我们将探索将 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:

{
    "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;
    
    // constructors/getters/setters
}

将 JSON 字符串转换为JsonNode
如果我们想从整个 JSON 中读取一个对象,我们可以使用 Jackson 的ObjectMapper 类来实现:

JsonNode rootNode = new ObjectMapper().readTree(jsonString);
JsonNode childNode = rootNode.get("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("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("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对象。

解串器的工作方式与其他方法类似,只是它可以提供关注点分离。此外,自定义反序列化器提供了灵活性,因为我们可以在调用代码中轻松地在反序列化器之间切换。