Jackson 比较两个JSON对象
1. 概述
在本文中,我们将看看使用Jackson(Java 的 JSON 处理库)比较两个 JSON 对象。
2. Maven依赖
首先,让我们添加*jackson-databind* Maven 依赖项:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
3. 使用 Jackson 比较两个 JSON 对象
我们将使用ObjectMapper 类将对象作为*JsonNode* 读取。
让我们创建一个ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
3.1. 比较两个简单的 JSON 对象
让我们从使用JsonNode.equals 方法开始。**equals()方法执行完整(深度)比较。
假设我们有一个定义为s1变量的 JSON 字符串:
{
"employee":
{
"id": "1212",
"fullName": "John Miles",
"age": 34
}
}
我们想将它与另一个 JSON s2进行比较:
{
"employee":
{
"id": "1212",
"age": 34,
"fullName": "John Miles"
}
}
让我们将输入 JSON 读取为JsonNode并进行比较:
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
需要注意的是,**即使输入 JSON 变量s1和s2中的属性顺序不同,equals()方法也会忽略顺序并将它们视为相等。
3.2. 将两个 JSON 对象与嵌套元素进行比较
接下来,我们将看到如何比较两个具有嵌套元素的 JSON 对象。
让我们从定义为s1变量的 JSON 开始:
{
"employee":
{
"id": "1212",
"fullName":"John Miles",
"age": 34,
"contact":
{
"email": "john@xyz.com",
"phone": "9999999999"
}
}
}
正如我们所见,JSON 包含一个嵌套元素contact。我们想将它与s2定义的另一个 JSON 进行比较:
{
"employee":
{
"id": "1212",
"age": 34,
"fullName": "John Miles",
"contact":
{
"email": "john@xyz.com",
"phone": "9999999999"
}
}
}
让我们将输入 JSON 读取为JsonNode并进行比较:
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
同样,我们应该注意到**equals()还可以将两个输入 JSON 对象与嵌套元素进行比较。
3.3. 比较两个包含列表元素的 JSON 对象
同样,我们也可以比较两个包含列表元素的 JSON 对象。
让我们考虑这个定义为s1的 JSON :
{
"employee":
{
"id": "1212",
"fullName": "John Miles",
"age": 34,
"skills": ["Java", "C++", "Python"]
}
}
我们将它与另一个 JSON s2进行比较:
{
"employee":
{
"id": "1212",
"age": 34,
"fullName": "John Miles",
"skills": ["Java", "C++", "Python"]
}
}
让我们将输入 JSON 读取为JsonNode并进行比较:
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
重要的是要知道两个列表元素只有在它们具有完全相同的顺序的相同值时才会被比较为相等。
4. 使用自定义比较器比较两个 JSON 对象
JsonNode.equals 在大多数情况下都能很好地工作。Jackson 还提供了JsonNode.equals(comparator, JsonNode) 来配置自定义 JavaComparator器对象。让我们了解如何使用自定义Comparator。
4.1. 自定义比较器来比较数值
让我们了解如何使用自定义Comparator来比较两个具有数值的 JSON 元素。
我们将使用这个 JSON 作为输入s1:
{
"name": "John",
"score": 5.0
}
让我们与另一个定义为s2的 JSON 进行比较:
{
"name": "John",
"score": 5
}
我们需要观察输入s1和s2中的属性score的值是不一样的。
让我们将输入 JSON 读取为JsonNode并进行比较:
JsonNode actualObj1 = mapper.readTree(s1);
JsonNode actualObj2 = mapper.readTree(s2);
assertNotEquals(actualObj1, actualObj2);
我们可以注意到,这两个对象并不相等。标准的*equals()*方法将值 5.0 和 5 视为不同。
但是,我们可以使用自定义Comparator来比较值 5 和 5.0 并将它们视为相等。
让我们首先创建一个Comparator来比较两个NumericNode对象:
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;
}
}
接下来,让我们看看如何使用这个Comparator:
NumericNodeComparator cmp = new NumericNodeComparator();
assertTrue(actualObj1.equals(cmp, actualObj2));
4.2. 自定义比较器来比较文本值
让我们看一下自定义Comparator的另一个示例,用于对两个 JSON 值进行不区分大小写的比较。
我们将使用这个 JSON 作为输入s1:
{
"name": "john",
"score": 5
}
让我们与另一个定义为s2的 JSON 进行比较:
{
"name": "JOHN",
"score": 5
}
正如我们所看到的,属性name在输入s1中是小写的,在s2中是大写的。
让我们首先创建一个Comparator来比较两个TextNode对象:
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 :
JsonNode actualObj1 = mapper.readTree(s1);
JsonNode actualObj2 = mapper.readTree(s2);
TextNodeComparator cmp = new TextNodeComparator();
assertNotEquals(actualObj1, actualObj2);
assertTrue(actualObj1.equals(cmp, actualObj2));
最后,我们可以看到,当输入的 JSON 元素值不完全相同但我们仍希望将它们视为相等时,比较两个 JSON 对象时使用自定义比较器对象非常有用。