Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing two JSON objects for equality ignoring child order in Java [closed]

Tags:

java

json

junit

People also ask

How do you know if two JSON objects are equal?

Comparing Json: 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.

Can we compare two JSON objects Java?

Compare JSON Objects with Custom ComparatorThe JsonNode. equals() method works fine for most of the cases in comparing two objects. However, Jackson provides one more variant of the equals() method, i.e., JsonNode. equals(comparator, JsonNode) for configuring the custom Java Comparator object.

Does JSON object preserve order Java?

As seen above in the JSONResponse, since object is an unordered set of name/value pairts, so JSONObject isn't preserving the order of my object's name/value pairs.

Does order matter in a JSON object?

The JSON RFC (RFC 4627) says that order of object members does not matter.


Try Skyscreamer's JSONAssert.

Its non-strict mode has two major advantages that make it less brittle:

  • Object extensibility (e.g. With an expected value of {id:1}, this would still pass: {id:1,moredata:'x'}.)
  • Loose array ordering (e.g. ['dog','cat']==['cat','dog'])

In strict mode it behaves more like json-lib's test class.

A test looks something like this:

@Test
public void testGetFriends() {
    JSONObject data = getRESTData("/friends/367.json");
    String expected = "{friends:[{id:123,name:\"Corby Page\"}"
        + ",{id:456,name:\"Solomon Duskis\"}]}";
    JSONAssert.assertEquals(expected, data, false);
}

The parameters in the JSONAssert.assertEquals() call are expectedJSONString, actualDataString, and isStrict.

The result messages are pretty clear, which is important when comparing really big JSON objects.


As a general architectural point, I usually advise against letting dependencies on a particular serialization format bleed out beyond your storage/networking layer; thus, I'd first recommend that you consider testing equality between your own application objects rather than their JSON manifestations.

Having said that, I'm currently a big fan of Jackson which my quick read of their ObjectNode.equals() implementation suggests does the set membership comparison that you want:

public boolean equals(Object o)
{
    if (o == this) return true;
    if (o == null) return false;
    if (o.getClass() != getClass()) {
        return false;
    }
    ObjectNode other = (ObjectNode) o;
    if (other.size() != size()) {
        return false;
    }
    if (_children != null) {
        for (Map.Entry<String, JsonNode> en : _children.entrySet()) {
            String key = en.getKey();
            JsonNode value = en.getValue();

            JsonNode otherValue = other.get(key);

            if (otherValue == null || !otherValue.equals(value)) {
                return false;
            }
        }
    }
    return true;
}

Using GSON

JsonParser parser = new JsonParser();
JsonElement o1 = parser.parse("{a : {a : 2}, b : 2}");
JsonElement o2 = parser.parse("{b : 2, a : {a : 2}}");
assertEquals(o1, o2);

Edit: Since GSON v2.8.6 the instance method JsonParser.parse is deprecated. You have to use the static method JsonParser.parseString:

JsonElement o1 = JsonParser.parseString("{a : {a : 2}, b : 2}");
JsonElement o2 = JsonParser.parseString("{b : 2, a : {a : 2}}");
assertEquals(o1, o2);

I would do the following,

JSONObject obj1 = /*json*/;
JSONObject obj2 = /*json*/;

ObjectMapper mapper = new ObjectMapper();

JsonNode tree1 = mapper.readTree(obj1.toString());
JsonNode tree2 = mapper.readTree(obj2.toString());

return tree1.equals(tree2);