前言
在日常开发中,我们经常去比较两个对象是否相等,如果此对象是josn反序列化的,那么还要对对象属性进行逐一比对,手写个工具类耗时耗力,那如何解决此类问题呢。
JsonNode.equals
节点对象的相等定义为完全(深度)值相等。这意味着可以通过比较根节点的相等性来比较完整的JSON树的相等性。
我们可以使用ObjectMapper类将Json字符串转成JsonNode,然后使用JsonNode的equals方法。
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonStr);
JsonNode.equals方法支持执行完整(深度)比较。
Example-1
/**
* 比较两个简单的 JSON 对象
*/
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\": {\n" +
" \"id\": \"10001\",\n" +
" \"name\": \"小明\",\n" +
" \"age\": 22\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\": {\n" +
" \"id\": \"10001\",\n" +
" \"age\": 22,\n" +
" \"name\": \"小明\"\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
System.out.println(jsonNode1.equals(jsonNode2));
}
我们可以发现上文中的name与age的在Json中的属性顺序不相同,jsonNode1.equals也会忽略顺序并将它们视为相等。
Example-2
/**
* 比较带有嵌套元素的两个 JSON 对象
*/
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\": {\n" +
" \"id\": \"10001\",\n" +
" \"name\": \"小明\",\n" +
" \"age\": 22,\n" +
" \"contact\": {\n" +
" \"email\": \"Duansg@163.com\",\n" +
" \"phone\": \"13912341234\"\n" +
" }\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\": {\n" +
" \"id\": \"10001\",\n" +
" \"age\": 22,\n" +
" \"name\": \"小明\",\n" +
" \"contact\": {\n" +
" \"email\": \"Duansg@163.com\",\n" +
" \"phone\": \"13912341234\"\n" +
" }\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
System.out.println(jsonNode1.equals(jsonNode2));
}
同样,我们也不难发现,jsonNode1.equals方法也可以比较两个具有嵌套元素的Json。
Example-3
/**
* 比较两个包含列表元素的 JSON 对象
*/
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\": {\n" +
" \"id\": \"10001\",\n" +
" \"name\": \"小明\",\n" +
" \"age\": 22,\n" +
" \"hobby\": [\"Java\", \"Python\"]\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\": {\n" +
" \"id\": \"10001\",\n" +
" \"age\": 22,\n" +
" \"name\": \"小明\",\n" +
" \"hobby\": [\"Java\", \"Python\"]\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
System.out.println(jsonNode1.equals(jsonNode2));
}
同样,我们也不难发现,jsonNode1.equals方法也可以比较两个具有数组元素的Json,但是需要注意的是,只有当两个数组中的元素顺序完全相同时,才会被比视为相等。
Custom Comparator
Jackson还提供了JsonNode.equals(Comparator,JsonNode)方法来配置自定义Comparator对象,用来满足一些自定义需求。
Example-1
/**
* 下述方法执行出来的结果是不相等的
*/
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\": {\n" +
" \"name\": \"小明\",\n" +
" \t\"age\": 22.0\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\": {\n" +
" \"name\": \"小明\",\n" +
" \t\"age\": 22\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
System.out.println(jsonNode1.equals(jsonNode2));
}
创建一个Comparator
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\": {\n" +
" \"name\": \"小明\",\n" +
" \t\"age\": 22.0\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\": {\n" +
" \"name\": \"小明\",\n" +
" \t\"age\": 22\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
NumericNodeComparator cmp = new NumericNodeComparator();
System.out.println(jsonNode1.equals(cmp, jsonNode2));
}
public static 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 = o1.asDouble();
Double d2 = o2.asDouble();
if (d1.compareTo(d2) == 0) {
return 0;
}
}
return 1;
}
}
Example-2
/**
* 下述方法执行出来的结果是不相等的
*/
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\":{\n" +
" \t\t\"name\": \"JACK\",\n" +
" \t\"age\": 22\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\":{\n" +
" \t\t\"name\": \"jack\",\n" +
" \t\"age\": 22\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
System.out.println(jsonNode1.equals(jsonNode2));
}
创建一个Comparator
public static void main(String[] args) throws IOException {
String user1 = "{\n" +
" \"user\":{\n" +
" \t\t\"name\": \"JACK\",\n" +
" \t\"age\": 22\n" +
" }\n" +
"}";
String user2 = "{\n" +
" \"user\":{\n" +
" \t\t\"name\": \"jack\",\n" +
" \t\"age\": 22\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode1 = mapper.readTree(user1);
JsonNode jsonNode2 = mapper.readTree(user2);
TextNodeComparator cmp = new TextNodeComparator();
System.out.println(jsonNode1.equals(cmp, jsonNode2));
}
public static 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 = o1.asText();
String s2 = o2.asText();
if (s1.equalsIgnoreCase(s2)) {
return 0;
}
}
return 1;
}
}
小结
当输入的Json元素值不完全相同时,但是你仍希望将它们视为相等时,就可以通过实现自定义比较器来进行处理。