1. Overview
In this article, we’ll have a look at comparing two JSON objects using Jackson – a JSON processing library for Java.
2. Maven Dependency
First, let’s add the jackson-databind Maven dependency:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
3. Using Jackson to Compare Two JSON Objects
We’ll be using the ObjectMapper class to read an object as a JsonNode.
Let’s create an ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
3.1. Compare Two Simple JSON Objects
Let’s begin by using the JsonNode.equals method. The equals() method performs a full (deep) comparison.
Suppose we have a JSON string defined as the s1 variable:
{ "employee": { "id": "1212", "fullName": "John Miles", "age": 34 } }
And we want to compare it with another JSON, s2:
{ "employee": { "id": "1212", "age": 34, "fullName": "John Miles" } }
Let’s read the input JSON as JsonNode and compare:
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
It’s important to note that even though the order of attributes in input JSON variables s1 and s2 is not the same, the equals() method ignores the order and treats them as equal.
3.2. Compare Two JSON Objects with a Nested Element
Next, we’ll see how to compare two JSON objects having nested elements.
Let’s begin with a JSON defined as the s1 variable:
{ "employee": { "id": "1212", "fullName":"John Miles", "age": 34, "contact": { "email": "john@xyz.com", "phone": "9999999999" } } }
As we can see, the JSON contains a nested element contact. We want to compare it with another JSON defined by s2:
{ "employee": { "id": "1212", "age": 34, "fullName": "John Miles", "contact": { "email": "john@xyz.com", "phone": "9999999999" } } }
Let’s read the input JSON as JsonNode and compare:
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
Again, we should notice that equals() can also compare two input JSON objects with nested elements.
3.3. Compare Two JSON Objects Containing a List Element
Similarly, we can also compare two JSON objects that contain a list element.
Let’s consider this JSON defined as s1:
{ "employee": { "id": "1212", "fullName": "John Miles", "age": 34, "skills": ["Java", "C++", "Python"] } }
We are comparing it with another JSON s2:
{ "employee": { "id": "1212", "age": 34, "fullName": "John Miles", "skills": ["Java", "C++", "Python"] } }
Let’s read the input JSON as JsonNode and compare:
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
It’s important to know that two list elements are only compared as equal if they have the same values in the exact same order.
4. Compare Two JSON Objects with a Custom Comparator
JsonNode.equals works quite well in most of the cases. Jackson also provides JsonNode.equals(comparator, JsonNode) to configure a custom Java Comparator object. Let’s understand how to use a custom Comparator.
4.1. Custom Comparator to Compare Numeric Values
Let’s understand how to use a custom Comparator to compare two JSON elements having numeric values.
We’ll use this JSON as input s1:
{ "name": "John", "score": 5.0 }
Let’s compare with another JSON defined as s2:
{ "name": "John", "score": 5 }
We need to observe that the values of attribute score in inputs s1 and s2 are not the same.
Let’s read the input JSON as JsonNode and compare:
JsonNode actualObj1 = mapper.readTree(s1); JsonNode actualObj2 = mapper.readTree(s2); assertNotEquals(actualObj1, actualObj2);
As we can notice, the two objects are not equal. The standard equals() method consider values 5.0 and 5 as different.
However, we can use a custom Comparator to compare values 5 and 5.0 and treat them as equal.
Let’s first create a Comparator to compare two NumericNode objects:
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; } }
Next, let’s see how to use this Comparator:
NumericNodeComparator cmp = new NumericNodeComparator(); assertTrue(actualObj1.equals(cmp, actualObj2));
4.2. Custom Comparator to Compare Text Values
Let’s see another example of a custom Comparator for a case-insensitive comparison of two JSON values.
We’ll use this JSON as input s1:
{ "name": "john", "score": 5 }
Let’s compare with another JSON defined as s2:
{ "name": "JOHN", "score": 5 }
As we can see the attribute name is lowercase in input s1 and uppercase in s2.
Let’s first create a Comparator to compare two TextNode objects:
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; } }
Let’s see how to compare s1 and s2 using TextNodeComparator:
JsonNode actualObj1 = mapper.readTree(s1); JsonNode actualObj2 = mapper.readTree(s2); TextNodeComparator cmp = new TextNodeComparator(); assertNotEquals(actualObj1, actualObj2); assertTrue(actualObj1.equals(cmp, actualObj2));
Finally, we can see using a custom comparator object while comparing two JSON objects can be very useful when the input JSON element value is not exactly the same but we still want to treat them as equal.
5. Conclusion
In this quick tutorial, we’ve seen how to use Jackson to compare two JSON objects and use a custom comparator.
Of course, as always, the full source code of all the examples discussed here can be found over on GitHub.