用Jackson比较两个JSON对象

Compare Two JSON Objects with Jackson

1.概述

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

2. Maven依赖

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

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

3.使用Jackson比较两个JSON对象

我们将使用ObjectMapper类将对象读取为JsonNode。

让我们创建一个ObjectMapper:

1
ObjectMapper mapper = new ObjectMapper();

3.1。比较两个简单的JSON对象

让我们从使用JsonNode.equals方法开始。 equals()方法执行完整(深度)比较。

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

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

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

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

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

1
assertEquals(mapper.readTree(s1), mapper.readTree(s2));

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

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

接下来,我们将看到如何比较两个具有嵌套元素的JSON对象。

让我们从定义为s1变量的JSON开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
   "employee":
    {
       "id":"1212",
       "fullName":"John Miles",
       "age": 34,
       "contact":
        {
           "email":"[emailprotected]",
           "phone":"9999999999"
        }
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
{
   "employee":
    {
       "id":"1212",
       "age": 34,
       "fullName":"John Miles",
       "contact":
        {
           "email":"[emailprotected]",
           "phone":"9999999999"
        }
    }
}

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

1
assertEquals(mapper.readTree(s1), mapper.readTree(s2));

同样,我们应该注意到equals()也可以将两个输入的JSON对象与嵌套元素进行比较。

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

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

让我们考虑定义为s1的JSON:

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

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

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

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

1
assertEquals(mapper.readTree(s1), mapper.readTree(s2));

重要的是要知道两个列表元素只有在具有完全相同顺序的相同值时才被比较。

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

JsonNode.equals在大多数情况下都能很好地工作。 Jackson还提供了JsonNode.equals(comparator,JsonNode)来配置自定义Java Comparator对象。让我们了解如何使用自定义比较器。

4.1。自定义比较器以比较数值

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

我们将使用此JSON作为输入s1:

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

让我们与定义为s2的另一个JSON进行比较:

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

我们需要观察到输入s1和s2中的属性得分的值不相同。

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

1
2
3
4
JsonNode actualObj1 = mapper.readTree(s1);
JsonNode actualObj2 = mapper.readTree(s2);

assertNotEquals(actualObj1, actualObj2);

我们可以注意到,两个对象不相等。标准的equals()方法将值5.0和5视为不同。

但是,我们可以使用自定义比较器比较值5和5.0并将它们视为相等。

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

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

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

1
2
NumericNodeComparator cmp = new NumericNodeComparator();
assertTrue(actualObj1.equals(cmp, actualObj2));

4.2。自定义比较器以比较文本值

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

我们将使用此JSON作为输入s1:

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

让我们与定义为s2的另一个JSON进行比较:

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

如我们所见,属性名称在输入s1中为小写,在s2中为大写。

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

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

让我们看看如何使用TextNodeComparator比较s1和s2:

1
2
3
4
5
6
7
JsonNode actualObj1 = mapper.readTree(s1);
JsonNode actualObj2 = mapper.readTree(s2);

TextNodeComparator cmp = new TextNodeComparator();

assertNotEquals(actualObj1, actualObj2);
assertTrue(actualObj1.equals(cmp, actualObj2));

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

5.结论

在本快速教程中,我们已经了解了如何使用Jackson来比较两个JSON对象并使用自定义比较器。

当然,与往常一样,此处讨论的所有示例的完整源代码都可以在GitHub上找到。