Jackson Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

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": "[email protected]",
            "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": "[email protected]",
            "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 considers 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.

Jackson bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!