Skip to content

Instantly share code, notes, and snippets.

@dmarcosl
Last active November 1, 2024 11:55
Show Gist options
  • Save dmarcosl/28f3691eb26c4ece73163664cef8a2b6 to your computer and use it in GitHub Desktop.
Save dmarcosl/28f3691eb26c4ece73163664cef8a2b6 to your computer and use it in GitHub Desktop.
Comparing 2 unordered jsons with Jackson
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.exceptions.JsonHandleException;
import java.util.Iterator;
import java.util.Map;
public class JsonUtils {
private static final ObjectMapper mapper = new ObjectMapper();
protected static JsonNode readJson(String json) throws JsonHandleException {
try {
return mapper.readTree(json);
} catch (JsonProcessingException e) {
throw new JsonHandleException(String.format("Error parsing json to JsonNode: %s", json), e);
}
}
public static boolean compareTwoJsons(String jsonStr1, String jsonStr2)
throws JsonHandleException {
JsonNode json1 = readJson(jsonStr1);
JsonNode json2 = readJson(jsonStr2);
return compareTwoJsonNodes(json1, json2);
}
private static boolean compareTwoJsonNodes(JsonNode json1, JsonNode json2) {
// Number of fields (object) / elements (array)
if (json1.size() != json2.size()) {
return false;
}
for (Iterator<Map.Entry<String, JsonNode>> it = json1.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
String key = entry.getKey();
JsonNode value1 = entry.getValue();
// Key exists in both
if (!json2.has(key)) {
return false;
}
JsonNode value2 = json2.get(key);
// If one is null and the other is not
if ((value1.isNull() || value2.isNull()) && value1.equals(value2)) {
return false;
}
// Length (object) / size (array)
if (value1.size() != value2.size()) {
return false;
}
if (value1.isArray()) {
// Compare each column of each row of both arrays to find a match regardless
// of the order of the row or column
for (int i = 0; i < value1.size(); i++) {
for (int j = 0; j < value2.size(); j++) {
if (compareTwoJsonNodes(value1.get(i), value2.get(j))) {
return true;
}
}
}
return false;
} else {
// Compare the class and the value
if (!value1.getClass().equals(value2.getClass())) {
return false;
} else if (!value1.equals(value2)) {
return false;
}
}
}
return true;
}
}
import static org.junit.jupiter.api.Assertions.*;
import com.exceptions.JsonHandleException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
class JsonUtilsTest {
@Test
void compareTwoJsons_depth1_same__true() {
var jsonStr1 = "{\"key1\": \"value1\", \"key2\": 123, \"key3\": true}";
var jsonStr2 = "{\"key1\": \"value1\", \"key2\": 123, \"key3\": true}";
assertTrue(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth1_same_unordered__true() {
var jsonStr1 = "{\"key1\": \"value1\", \"key2\": 123, \"key3\": true}";
var jsonStr2 = "{\"key3\": true, \"key1\": \"value1\", \"key2\": 123}";
assertTrue(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth1_different_keys__false() {
var jsonStr1 = "{\"key1\": \"value1\", \"key2\": 123, \"key3\": true}";
var jsonStr2 = "{\"key4\": \"value1\", \"key5\": 123, \"key6\": true}";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth1_different_size__false() {
var jsonStr1 = "{\"key1\": \"value1\", \"key2\": 123, \"key3\": true}";
var jsonStr2 = "{\"key1\": \"value1\", \"key2\": 123}";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth1_nulls__false() {
var jsonStr1 = "{\"key1\": null, \"key2\": null, \"key3\": null}";
var jsonStr2 = "{\"key1\": null, \"key2\": 123, \"key3\": null}";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth1_different_class__false() {
var jsonStr1 = "{\"key1\": \"value1\"}";
var jsonStr2 = "{\"key1\": false}";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth1_different_value__false() {
var jsonStr1 = "{\"key1\": \"value1\"}";
var jsonStr2 = "{\"key1\": \"valueDifferent\"}";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth2_same__true() {
var jsonStr1 =
"""
{
"appconfig": [
{ "key": "key1", "value": "value", "type": "String" },
{ "key": "key2", "value": true, "type": "Boolean" },
{ "key": "key3", "value": 1, "type": "Integer" }
]
}
""";
var jsonStr2 =
"""
{
"appconfig": [
{ "key": "key1", "value": "value", "type": "String" },
{ "key": "key2", "value": true, "type": "Boolean" },
{ "key": "key3", "value": 1, "type": "Integer" }
]
}
""";
assertTrue(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth2_same_unordered__true() {
var jsonStr1 =
"""
{
"appconfig": [
{ "key": "key1", "value": "value", "type": "String" },
{ "key": "key2", "value": true, "type": "Boolean" },
{ "key": "key3", "value": 1, "type": "Integer" }
]
}
""";
var jsonStr2 =
"""
{
"appconfig": [
{ "value": 1, "key": "key3", "type": "Integer" },
{ "type": "Boolean", "key": "key2", "value": true },
{ "key": "key1", "type": "String", "value": "value" }
]
}
""";
assertTrue(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth2_different_size__false() {
var jsonStr1 =
"""
{
"appconfig": [
{ "key": "key1", "value": "value", "type": "String" },
{ "key": "key2", "value": true, "type": "Boolean" },
{ "key": "key3", "value": 1, "type": "Integer" }
]
}
""";
var jsonStr2 =
"""
{
"appconfig": [
{ "key": "key2", "value": true, "type": "Boolean" },
{ "key": "key1", "value": "value", "type": "String" }
]
}
""";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
@Test
void compareTwoJsons_depth2_different_keys__false() {
var jsonStr1 =
"""
{
"appconfig": [
{ "key": "key1", "value": "value", "type": "String" },
{ "key": "key2", "value": true, "type": "Boolean" },
{ "key": "key3", "value": 1, "type": "Integer" }
]
}
""";
var jsonStr2 =
"""
{
"appconfig": [
{ "key": "key4", "value": 1, "type": "Integer" },
{ "key": "key5", "value": true, "type": "Boolean" },
{ "key": "key6", "value": "value", "type": "String" }
]
}
""";
assertFalse(JsonUtils.compareTwoJsons(jsonStr1, jsonStr2));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment