In this post, I am going to explain how to compare two json documents in Java.
Approach 1: Using Guava’s Maps.difference(Map<K, V>, Map<K, V>) method.
a. Convert json string to a map
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> leftMap = gson.fromJson(json1, type);
b. Use ‘Maps.difference’ method to get the differences between two maps.
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
c. Print MapDifference object.
private static void printMapDifference(MapDifference<String, Object> difference) {
System.out.println("\n\nEntries only on left\n--------------------------");
difference.entriesOnlyOnLeft().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries only on right\n--------------------------");
difference.entriesOnlyOnRight().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries differing\n--------------------------");
difference.entriesDiffering().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries in common\n--------------------------");
difference.entriesInCommon().forEach((key, value) -> System.out.println(key + ": " + value));
}
Find the below working application.
Employee.java
package com.sample.app;
public class Employee {
private int id;
private String firstName;
private String lastName;
private Integer age;
public Employee() {
}
public Employee(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Employee(int id, String firstName, String lastName, Integer age) {
this(id, firstName, lastName);
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
App.java
package com.sample.app;
import java.lang.reflect.Type;
import java.util.Map;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
public class App {
private static void printMapDifference(MapDifference<String, Object> difference) {
System.out.println("\n\nEntries only on left\n--------------------------");
difference.entriesOnlyOnLeft().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries only on right\n--------------------------");
difference.entriesOnlyOnRight().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries differing\n--------------------------");
difference.entriesDiffering().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries in common\n--------------------------");
difference.entriesInCommon().forEach((key, value) -> System.out.println(key + ": " + value));
}
public static void main(String args[]) {
Employee emp1 = new Employee(1, "Krishna", "Gurram", 31);
Employee emp2 = new Employee(1, "Ram", "Gurram");
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json1 = gson.toJson(emp1);
String json2 = gson.toJson(emp2);
System.out.println(json1);
System.out.println(json2);
Type type = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> leftMap = gson.fromJson(json1, type);
Map<String, Object> rightMap = gson.fromJson(json2, type);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
printMapDifference(difference);
}
}
Output
{
"id": 1,
"firstName": "Krishna",
"lastName": "Gurram",
"age": 31
}
{
"id": 1,
"firstName": "Ram",
"lastName": "Gurram"
}
Entries only on left
--------------------------
age: 31.0
Entries only on right
--------------------------
Entries differing
--------------------------
firstName: (Krishna, Ram)
Entries in common
--------------------------
lastName: Gurram
id: 1.0
Problem with above approach
When it comes to the nested objects, the output doesn’t look meaningful.
Let us see this with an example.
Address.java
package com.sample.app;
public class Address {
private String city;
private String country;
private String street;
public Address() {
}
public Address(String street, String city, String country) {
this.city = city;
this.country = country;
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
Employee.java
package com.sample.app;
import java.util.List;
public class Employee {
private int id;
private String firstName;
private String lastName;
private Integer age;
private List<Address> addresses;
public Employee() {
}
public Employee(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Employee(int id, String firstName, String lastName, Integer age) {
this(id, firstName, lastName);
this.age = age;
}
public Employee(int id, String firstName, String lastName, Integer age, List<Address> addresses) {
this(id, firstName, lastName, age);
this.addresses = addresses;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<Address> getAddresses() {
return addresses;
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
}
App.java
package com.sample.app;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Map;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.util.*;
public class App {
private static void printMapDifference(MapDifference<String, Object> difference) {
System.out.println("\n\nEntries only on left\n--------------------------");
difference.entriesOnlyOnLeft().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries only on right\n--------------------------");
difference.entriesOnlyOnRight().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries differing\n--------------------------");
difference.entriesDiffering().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries in common\n--------------------------");
difference.entriesInCommon().forEach((key, value) -> System.out.println(key + ": " + value));
}
public static void main(String args[]) {
Address addr1 = new Address("Chowdeswari street", "Bangalore", "India");
Address addr2 = new Address("Ramappa street", "Hyderabad", "India");
Address addr3 = new Address("PTR street", "Gudivada", "India");
List<Address> addresses1 = Arrays.asList(addr1, addr2);
List<Address> addresses2 = Arrays.asList(addr1, addr3);
Employee emp1 = new Employee(1, "Krishna", "Gurram", 31, addresses1);
Employee emp2 = new Employee(1, "Ram", "Gurram", 24, addresses2);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json1 = gson.toJson(emp1);
String json2 = gson.toJson(emp2);
System.out.println(json1);
System.out.println(json2);
Type type = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> leftMap = gson.fromJson(json1, type);
Map<String, Object> rightMap = gson.fromJson(json2, type);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
printMapDifference(difference);
}
}
Output
{
"id": 1,
"firstName": "Krishna",
"lastName": "Gurram",
"age": 31,
"addresses": [
{
"city": "Bangalore",
"country": "India",
"street": "Chowdeswari street"
},
{
"city": "Hyderabad",
"country": "India",
"street": "Ramappa street"
}
]
}
{
"id": 1,
"firstName": "Ram",
"lastName": "Gurram",
"age": 24,
"addresses": [
{
"city": "Bangalore",
"country": "India",
"street": "Chowdeswari street"
},
{
"city": "Gudivada",
"country": "India",
"street": "PTR street"
}
]
}
Entries only on left
--------------------------
Entries only on right
--------------------------
Entries differing
--------------------------
firstName: (Krishna, Ram)
addresses: ([{city=Bangalore, country=India, street=Chowdeswari street}, {city=Hyderabad, country=India, street=Ramappa street}], [{city=Bangalore, country=India, street=Chowdeswari street}, {city=Gudivada, country=India, street=PTR street}])
age: (31.0, 24.0)
Entries in common
--------------------------
lastName: Gurram
id: 1.0
We can get more meaningful output by flattening the map.
FlatMapUtil.java
package com.sample.app;
import java.util.AbstractMap.SimpleEntry;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class FlatMapUtil {
public static Map<String, Object> flatten(Map<String, Object> mapToFlatten) {
return mapToFlatten.entrySet().stream().flatMap(FlatMapUtil::flatten).collect(LinkedHashMap::new,
(map, entry) -> map.put(entry.getKey(), entry.getValue()), LinkedHashMap::putAll);
}
private static Stream<Entry<String, Object>> flatten(Map.Entry<String, Object> entry) {
if (entry == null) {
return Stream.empty();
}
Object value = entry.getValue();
if (value instanceof Map<?, ?>) {
Map<?, ?> properties = (Map<?, ?>) value;
return properties.entrySet().stream()
.flatMap(e -> flatten(new SimpleEntry<>(entry.getKey() + "." + e.getKey(), e.getValue())));
}
if (value instanceof List<?>) {
List<?> list = (List<?>) value;
return IntStream.range(0, list.size())
.mapToObj(i -> new SimpleEntry<String, Object>(entry.getKey() + "[" + i + "]", list.get(i)))
.flatMap(FlatMapUtil::flatten);
}
return Stream.of(entry);
}
}
App.java
package com.sample.app;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Map;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.util.*;
public class App {
private static void printMapDifference(MapDifference<String, Object> difference) {
System.out.println("\n\nEntries only on left\n--------------------------");
difference.entriesOnlyOnLeft().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries only on right\n--------------------------");
difference.entriesOnlyOnRight().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries differing\n--------------------------");
difference.entriesDiffering().forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries in common\n--------------------------");
difference.entriesInCommon().forEach((key, value) -> System.out.println(key + ": " + value));
}
public static void main(String args[]) {
Address addr1 = new Address("Chowdeswari street", "Bangalore", "India");
Address addr2 = new Address("Ramappa street", "Hyderabad", "India");
Address addr3 = new Address("PTR street", "Gudivada", "India");
List<Address> addresses1 = Arrays.asList(addr1, addr2);
List<Address> addresses2 = Arrays.asList(addr1, addr3);
Employee emp1 = new Employee(1, "Krishna", "Gurram", 31, addresses1);
Employee emp2 = new Employee(1, "Ram", "Gurram", 24, addresses2);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json1 = gson.toJson(emp1);
String json2 = gson.toJson(emp2);
System.out.println(json1);
System.out.println(json2);
Type type = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> leftMap = gson.fromJson(json1, type);
Map<String, Object> rightMap = gson.fromJson(json2, type);
leftMap = FlatMapUtil.flatten(leftMap);
rightMap = FlatMapUtil.flatten(rightMap);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
printMapDifference(difference);
}
}
Output
{
"id": 1,
"firstName": "Krishna",
"lastName": "Gurram",
"age": 31,
"addresses": [
{
"city": "Bangalore",
"country": "India",
"street": "Chowdeswari street"
},
{
"city": "Hyderabad",
"country": "India",
"street": "Ramappa street"
}
]
}
{
"id": 1,
"firstName": "Ram",
"lastName": "Gurram",
"age": 24,
"addresses": [
{
"city": "Bangalore",
"country": "India",
"street": "Chowdeswari street"
},
{
"city": "Gudivada",
"country": "India",
"street": "PTR street"
}
]
}
Entries only on left
--------------------------
Entries only on right
--------------------------
Entries differing
--------------------------
firstName: (Krishna, Ram)
addresses[1].city: (Hyderabad, Gudivada)
addresses[1].street: (Ramappa street, PTR street)
age: (31.0, 24.0)
Entries in common
--------------------------
addresses[0].city: Bangalore
lastName: Gurram
addresses[0].street: Chowdeswari street
addresses[0].country: India
id: 1.0
addresses[1].country: India
No comments:
Post a Comment