I want to compare two JSON strings in Java 8 for equality, but ignore specific known nodes which contain values which are expected to be different and are a tolerated difference e.g. timestamp. Currently using JSONAssert v1.5.0 from org.SkyScreamer, I'm able to 'ignore' a number of these nodes, but cannot 'ignore' nodes within an array.
What I would like is to extend my current JSONComparator to include a Customization which has its first 'path' parameter having an array address.
JSONComparator customisedJobComparator = new CustomComparator(JSONCompareMode.NON_EXTENSIBLE,
new Customization("id", (o1, o2) -> true),
new Customization("appointmentBookedDate.$date", (o1, o2) -> true),
...
new Customization("someArray[n].timestamp", (o1, o2) -> true) //<--- this is wrong, what is the correct way for this path address?
);
The code below is my attempt at proving a solution; both expected/actual JSON strings are identical except for anArray[].id values. I want this test to pass, but is failing with error: java.lang.AssertionError: anArray[0] Could not find match for element {"id":"valueA"}
@Test
public void compareJsonStrIgnoringDiffInArray() {
String errorMsg = "";
String expectedJsonStr = "{\"anArray\": [{\"id\": \"valueA\"}, {\"colour\": \"Blue\"}]}";
String actualJsonStr = "{\"anArray\": [{\"id\": \"valueB\"}, {\"colour\": \"Blue\"}]}";
//Create custom comparator which compares two json strings but ignores reporting any differences for anArray[n].id values
//as they are a tolerated difference
Customization customization = new Customization("anArray[n].id", (o1, o2) -> true);
JSONComparator customisedComparator = new CustomComparator(JSONCompareMode.NON_EXTENSIBLE, customization);
JSONAssert.assertEquals(errorMsg, expectedJsonStr, actualJsonStr, customisedComparator);
}
Compare Two JSON Objects With a Custom Comparatorequals works quite well in most cases. Jackson also provides JsonNode. equals(comparator, JsonNode) to configure a custom Java Comparator object.
The comparison mode LENIENT means that even if the actual JSON contains extended fields, the test will still pass: String actual = "{id:123, name:\"John\", zip:\"33025\"}"; JSONAssert.assertEquals( "{id:123,name:\"John\"}", actual, JSONCompareMode.LENIENT);
Comparing json is quite simple, we can use '==' operator, Note: '==' and 'is' operator are not same, '==' operator is use to check equality of values , whereas 'is' operator is used to check reference equality, hence one should use '==' operator, 'is' operator will not give expected result.
After some digging in the javadoc for JSONAssert, I saw an example that used an array of objects. From that example I was able to modify your test case:
@Test
public void compareJsonStrIgnoringDiffInArray() throws JSONException {
String errorMsg = "";
String expectedJsonStr = "{\"anArray\": [{\"id\": \"valueA\"}, {\"colour\": \"Blue\"}]}";
String actualJsonStr = "{\"anArray\": [{\"id\": \"valueB\"}, {\"colour\": \"Blue\"}]}";
//Create custom comparator which compares two json strings but ignores reporting any differences for anArray[n].id values
//as they are a tolerated difference
ArrayValueMatcher<Object> arrValMatch = new ArrayValueMatcher<>(new CustomComparator(
JSONCompareMode.NON_EXTENSIBLE,
new Customization("anArray[*].id", (o1, o2) -> true)));
Customization arrayValueMatchCustomization = new Customization("anArray", arrValMatch);
CustomComparator customArrayValueComparator = new CustomComparator(
JSONCompareMode.NON_EXTENSIBLE,
arrayValueMatchCustomization);
JSONAssert.assertEquals(expectedJsonStr, actualJsonStr, customArrayValueComparator);
}
In case of my requirements, need to ignore the fields businessCorrelationId
present only once, effectiveStartDate
present in each node of data
.
{
"messageElements": {
"messageStatus": "SUCCESS",
"businessCorrelationId": "a80337639eb40758",
"errorList": []
},
"data": [
{
"referenceId": 1,
"category": "CAT1",
"subCategory": "SUB1",
"effectiveStartDate": "2021-02-08T00:00:00",
"activeFlg": true,
"version": 1
},
{
"referenceId": 2,
"category": "CAT2",
"subCategory": "SUB2",
"effectiveStartDate": "2021-02-08T00:00:00",
"effectiveEndDate": null,
"activeFlg": true,
"version": 1
},
{
"referenceId": 3,
"category": "CAT3",
"subCategory": "SUB3",
"effectiveStartDate": "2021-02-08T00:00:00",
"activeFlg": true,
"version": 1
}
],
"tenant": {
"tenantId": null,
"timeZoneOffset": null,
"name": null
}
}
Below code worked fine.
JSONAssert.assertEquals(expectedJson, actualJson, new CustomComparator(JSONCompareMode.LENIENT,
new Customization("data[*].createdTimestamp", (ct1, ct2) -> true),
new Customization("messageElements.businessCorrelationId", (c1, c2) -> true)));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With