Compare Two JSON Objects with Jackson

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.11.1</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 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.

Related posts:

XML-Based Injection in Spring
Adding a Newline Character to a String in Java
Java Program to Solve the Fractional Knapsack Problem
Java Program to Compute Discrete Fourier Transform Using Naive Approach
Guide to CopyOnWriteArrayList
Java Program to find the number of occurrences of a given number using Binary Search approach
Java Program to Implement Hash Tables with Double Hashing
Spring Boot: Customize the Jackson ObjectMapper
Java Program to Implement Repeated Squaring Algorithm
Java program to Implement Tree Set
Java Program to Implement Coppersmith Freivald’s Algorithm
Java Program to Implement Slicker Algorithm that avoids Triangulation to Find Area of a Polygon
Convert Hex to ASCII in Java
Using the Map.Entry Java Class
Spring Boot - Interceptor
A Guide to Java HashMap
Dynamic Proxies in Java
Introduction to Java Serialization
Period and Duration in Java
Vấn đề Nhà sản xuất (Producer) – Người tiêu dùng (Consumer) và đồng bộ hóa các luồng trong Java
HttpClient Basic Authentication
Send email with JavaMail
Java Program to Perform Postorder Non-Recursive Traversal of a Given Binary Tree
Lớp LinkedHashMap trong Java
Build a REST API with Spring and Java Config
Java Program to Implement Flood Fill Algorithm
Collect a Java Stream to an Immutable Collection
Java Program to Find Number of Spanning Trees in a Complete Bipartite Graph
Hướng dẫn Java Design Pattern – Visitor
Assert an Exception is Thrown in JUnit 4 and 5
Java Program to Implement Segment Tree
Java Program to Implement Cartesian Tree