在本教程中,我们将探索将 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对象。
解串器的工作方式与其他方法类似,只是它可以提供关注点分离。此外,自定义反序列化器提供了灵活性,因为我们可以在调用代码中轻松地在反序列化器之间切换。