概述

在本文中,我们将使用 Jackson(Java 的 JSON 处理库),比较两个 JSON 对象。

Maven 依赖

首先,让我们添加 jackson-databind Maven 依赖项:

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-databind</artifactId>
  4. <version>2.11.1</version>
  5. </dependency>

使用 Jackson 比较两个 JSON 对象

我们将使用 ObjectMapper 类将 JSON 字符串转成 JsonNode,然后使用 JsonNode 的 equals 方法。

  1. ObjectMapper mapper = new ObjectMapper();
  2. JsonNode jsonNode = mapper.readTree(jsonStr);

JsonNode.equals 方法支持执行完整(深度)比较。

比较两个简单的 JSON 对象

假设我们有一个定义为 s1 变量的 JSON 字符串:

  1. {
  2. "employee": {
  3. "id": "1212",
  4. "fullName": "John Miles",
  5. "age": 34
  6. }
  7. }

我们将其与另一个 JSON s2 进行比较:

  1. {
  2. "employee": {
  3. "id": "1212",
  4. "age": 34,
  5. "fullName": "John Miles"
  6. }
  7. }

将输入的 JSON 读取为 JsonNode 并进行比较:

  1. JsonNode jsonNode1 = mapper.readTree(s1);
  2. JsonNode jsonNode2 = mapper.readTree(s2);
  3. System.out.println(jsonNode1.equals(jsonNode2));

需要注意的是即使输入的 JSON 变量 s1 和 s2 中的属性顺序不相同,equals() 方法也会忽略顺序并将它们视为相等。

比较带有嵌套元素的两个 JSON 对象

假设我们有一个定义为 s1 变量的 JSON 字符串:

  1. {
  2. "employee": {
  3. "id": "1212",
  4. "fullName": "John Miles",
  5. "age": 34,
  6. "contact": {
  7. "email": "john@xyz.com",
  8. "phone": "9999999999"
  9. }
  10. }
  11. }

如我们所见,JSON 包含一个嵌套元素联系人。我们将其与另一个 JSON s2 进行比较:

  1. {
  2. "employee": {
  3. "id": "1212",
  4. "age": 34,
  5. "fullName": "John Miles",
  6. "contact": {
  7. "email": "john@xyz.com",
  8. "phone": "9999999999"
  9. }
  10. }
  11. }

将输入的 JSON 读取为 JsonNode 并进行比较:

  1. JsonNode jsonNode1 = mapper.readTree(s1);
  2. JsonNode jsonNode2 = mapper.readTree(s2);
  3. System.out.println(jsonNode1.equals(jsonNode2));

同样,我们应该注意到 equals() 方法也可以比较两个具有嵌套元素的 JSON 对象。

比较两个包含列表元素的 JSON 对象

同样,我们还可以比较两个包含 List 元素的 JSON 对象。

假设我们有一个定义为 s1 变量的 JSON 字符串:

  1. {
  2. "employee": {
  3. "id": "1212",
  4. "fullName": "John Miles",
  5. "age": 34,
  6. "skills": ["Java", "C++", "Python"]
  7. }
  8. }

我们将其与另一个 JSON s2 进行比较:

  1. {
  2. "employee": {
  3. "id": "1212",
  4. "age": 34,
  5. "fullName": "John Miles",
  6. "skills": ["Java", "C++", "Python"]
  7. }
  8. }

将输入的 JSON 读取为 JsonNode 并进行比较:

  1. JsonNode jsonNode1 = mapper.readTree(s1);
  2. JsonNode jsonNode2 = mapper.readTree(s2);
  3. System.out.println(jsonNode1.equals(jsonNode2));

需要注意的是,只有当两个列表元素的值的顺序完全相同时,才会被比视为相等。

使用自定义比较器比较两个 JSON 对象

在大多数情况下,JsonNode.equals(JsonNode) 方法能够满足要求了。

Jackson 还提供了 JsonNode.equals(``Comparator``,JsonNode) 方法来配置自定义 Java Comparator 对象,用来满足一些自定义需求。

自定义比较器来比较数字值

让我们了解如何使用自定义比较器来比较两个具有数字值的 JSON 元素。

假设我们有一个定义为 s1 变量的 JSON 字符串:

  1. {
  2. "name": "John",
  3. "score": 5.0
  4. }

我们将其与另一个 JSON s2 进行比较:

  1. {
  2. "name": "John",
  3. "score": 5
  4. }

将输入的 JSON 读取为 JsonNode 并进行比较:

  1. JsonNode jsonNode1 = mapper.readTree(s1);
  2. JsonNode jsonNode2 = mapper.readTree(s2);
  3. System.out.println(jsonNode1.equals(jsonNode2));

我们注意到,两个 JSON 对象不相等,标准的 equals() 方法认为 5.0 和 5 是不相同的。

但是,我们可以自定义比较器,将 5.0 和 5 视为相同的值。

首先,我们创建一个 Comparator 来比较两个 NumericNode 对象:

  1. public class NumericNodeComparator implements Comparator<JsonNode> {
  2. @Override
  3. public int compare(JsonNode o1, JsonNode o2) {
  4. if (o1.equals(o2)) {
  5. return 0;
  6. }
  7. if ((o1 instanceof NumericNode) && (o2 instanceof NumericNode)) {
  8. Double d1 = ((NumericNode) o1).asDouble();
  9. Double d2 = ((NumericNode) o2).asDouble();
  10. if (d1.compareTo(d2) == 0) {
  11. return 0;
  12. }
  13. }
  14. return 1;
  15. }
  16. }

接下来,让我们看看如何使用此比较器:

  1. NumericNodeComparator cmp = new NumericNodeComparator();
  2. JsonNode jsonNode1 = mapper.readTree(s1);
  3. JsonNode jsonNode2 = mapper.readTree(s2);
  4. System.out.println(jsonNode1.equals(cmp, jsonNode2));

自定义比较器来比较文本值

让我们看一下自定义比较器的另一个示例,该示例比较两个 JSON 值时是否区分大小写。

假设我们有一个定义为 s1 变量的 JSON 字符串:

  1. {
  2. "name": "john",
  3. "score": 5
  4. }

我们将其与另一个 JSON s2 进行比较:

  1. {
  2. "name": "JOHN",
  3. "score": 5
  4. }

如我们所见,属性 name 在 s1 中为小写,在 s2 中为大写。

创建一个 Comparator 来比较两个 TextNode 对象:

  1. public class TextNodeComparator implements Comparator<JsonNode> {
  2. @Override
  3. public int compare(JsonNode o1, JsonNode o2) {
  4. if (o1.equals(o2)) {
  5. return 0;
  6. }
  7. if ((o1 instanceof TextNode) && (o2 instanceof TextNode)) {
  8. String s1 = ((TextNode) o1).asText();
  9. String s2 = ((TextNode) o2).asText();
  10. if (s1.equalsIgnoreCase(s2)) {
  11. return 0;
  12. }
  13. }
  14. return 1;
  15. }
  16. }

接下来,让我们看看如何使用此比较器:

  1. TextNodeComparator cmp = new TextNodeComparator();
  2. JsonNode jsonNode1 = mapper.readTree(s1);
  3. JsonNode jsonNode2 = mapper.readTree(s2);
  4. System.out.println(jsonNode1.equals(cmp, jsonNode2));

在输入的 JSON 元素值不完全相同但我们仍希望将它们视为相等时,在比较两个 JSON 对象时使用自定义比较器对象非常有用。

转载

https://www.baeldung.com/jackson-compare-two-json-objects

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/psygdn 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。