Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignore specific nodes/attributes while comparing two JSONs

I want to compare two JSON strings which is a huge hierarchy and want to know where they differ in values. But some values are generated at runtime and are dynamic. I want to ignore those particular nodes from my comparison.

I am currently using JSONAssert from org.SkyScreamer to do the comparison. It gives me nice console output but does not ignore any attributes.

for ex.

java.lang.AssertionError messageHeader.sentTime expected:null got:09082016 18:49:41.123 

Now this comes dynamic and should be ignored. Something like

JSONAssert.assertEquals(expectedJSONString, actualJSONString,JSONCompareMode, *list of attributes to be ignored*) 

It would be great if someone suggests a solution in JSONAssert. However other ways are also welcome.

like image 423
Prateik Avatar asked Aug 09 '16 14:08

Prateik


People also ask

How do I compare two Jsonobjects?

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.

How do I compare two JSON objects in Node JS?

Your first code step would be to convert the JSON string to an object, using JSON. parse . Then you can use Object. keys to get all keys from the first object, and you can loop over these keys to see the difference in values in the two objects.

How do I compare two JSON lists?

Use json. dumps() and the equal-to operator to compare JSON objects regardless of order. Call json. dumps(json_object, sort_keys) with sort_keys set to True on each json_object to return the object with its key-value pairs sorted in ascending order by the keys.


1 Answers

You can use Customization for this. For example, if you need to ignore a top-level attribute named "timestamp" use:

JSONAssert.assertEquals(expectedResponseBody, responseBody,             new CustomComparator(JSONCompareMode.LENIENT,                 new Customization("timestamp", (o1, o2) -> true))); 

It's also possible to use path expressions like "entry.id". In your Customization you can use whatever method you like to compare the two values. The example above always returns true, no matter what the expected value and the actual value are. You could do more complicated stuff there if you need to.

It is perfectly fine to ignore that values of multiple attributes, for example:

@Test public void ignoringMultipleAttributesWorks() throws JSONException {     String expected = "{\"timestamp\":1234567, \"a\":5, \"b\":3 }";     String actual = "{\"timestamp\":987654, \"a\":1, \"b\":3 }";      JSONAssert.assertEquals(expected, actual,             new CustomComparator(JSONCompareMode.LENIENT,                     new Customization("timestamp", (o1, o2) -> true),                     new Customization("a", (o1, o2) -> true)             )); } 

There is one caveat when using Customizations: The attribute whose value is to be compared in a custom way has to be present in the actual JSON. If you want the comparison to succeed even if the attribute is not present at all you would have to override CustomComparator for example like this:

@Test public void extendingCustomComparatorToAllowToCompletelyIgnoreCertainAttributes() throws JSONException {     // AttributeIgnoringComparator completely ignores some of the expected attributes     class AttributeIgnoringComparator extends CustomComparator{         private final Set<String> attributesToIgnore;          private AttributeIgnoringComparator(JSONCompareMode mode, Set<String> attributesToIgnore, Customization... customizations) {             super(mode, customizations);             this.attributesToIgnore = attributesToIgnore;         }          protected void checkJsonObjectKeysExpectedInActual(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) throws JSONException {             Set<String> expectedKeys = getKeys(expected);             expectedKeys.removeAll(attributesToIgnore);             for (String key : expectedKeys) {                 Object expectedValue = expected.get(key);                 if (actual.has(key)) {                     Object actualValue = actual.get(key);                     compareValues(qualify(prefix, key), expectedValue, actualValue, result);                 } else {                     result.missing(prefix, key);                 }             }         }     }      String expected = "{\"timestamp\":1234567, \"a\":5}";     String actual = "{\"a\":5}";      JSONAssert.assertEquals(expected, actual,             new AttributeIgnoringComparator(JSONCompareMode.LENIENT,                     new HashSet<>(Arrays.asList("timestamp")))             ); }  

(With this approach you still could use Customizations to compare other attributes' values in the way you want.)

like image 87
dknaus Avatar answered Oct 02 '22 21:10

dknaus