我正在寻找一个JSON解析库,支持比较忽略子顺序的两个JSON对象,特别是用于从web服务返回的单元测试JSON。
有任何主要的JSON库支持这一点吗?org。Json库只是做一个引用比较。
我正在寻找一个JSON解析库,支持比较忽略子顺序的两个JSON对象,特别是用于从web服务返回的单元测试JSON。
有任何主要的JSON库支持这一点吗?org。Json库只是做一个引用比较。
当前回答
使用这个库:https://github.com/lukas-krecan/JsonUnit
Pom:
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>2.24.0</version>
<scope>test</scope>
</dependency>
IGNORING_ARRAY_ORDER -忽略数组中的顺序
assertThatJson("{\"test\":[1,2,3]}")
.when(Option.IGNORING_ARRAY_ORDER)
.isEqualTo("{\"test\": [3,2,1]}");
其他回答
其他方法似乎都不太合适,所以我写下了这个:
private boolean jsonEquals(JsonNode actualJson, JsonNode expectJson) {
if(actualJson.getNodeType() != expectJson.getNodeType()) return false;
switch(expectJson.getNodeType()) {
case NUMBER:
return actualJson.asDouble() == expectJson.asDouble();
case STRING:
case BOOLEAN:
return actualJson.asText().equals(expectJson.asText());
case OBJECT:
if(actualJson.size() != expectJson.size()) return false;
Iterator<String> fieldIterator = actualJson.fieldNames();
while(fieldIterator.hasNext()) {
String fieldName = fieldIterator.next();
if(!jsonEquals(actualJson.get(fieldName), expectJson.get(fieldName))) {
return false;
}
}
break;
case ARRAY:
if(actualJson.size() != expectJson.size()) return false;
List<JsonNode> remaining = new ArrayList<>();
expectJson.forEach(remaining::add);
// O(N^2)
for(int i=0; i < actualJson.size(); ++i) {
boolean oneEquals = false;
for(int j=0; j < remaining.size(); ++j) {
if(jsonEquals(actualJson.get(i), remaining.get(j))) {
oneEquals = true;
remaining.remove(j);
break;
}
}
if(!oneEquals) return false;
}
break;
default:
throw new IllegalStateException();
}
return true;
}
org。我已经推出了自己的解决方案,一个与JSONObject实例进行比较的方法。我在那个项目中没有使用复杂的JSON对象,所以我不知道这是否适用于所有场景。此外,鉴于我在单元测试中使用了这个功能,我没有在优化方面投入精力。下面就是:
public static boolean jsonObjsAreEqual (JSONObject js1, JSONObject js2) throws JSONException {
if (js1 == null || js2 == null) {
return (js1 == js2);
}
List<String> l1 = Arrays.asList(JSONObject.getNames(js1));
Collections.sort(l1);
List<String> l2 = Arrays.asList(JSONObject.getNames(js2));
Collections.sort(l2);
if (!l1.equals(l2)) {
return false;
}
for (String key : l1) {
Object val1 = js1.get(key);
Object val2 = js2.get(key);
if (val1 instanceof JSONObject) {
if (!(val2 instanceof JSONObject)) {
return false;
}
if (!jsonObjsAreEqual((JSONObject)val1, (JSONObject)val2)) {
return false;
}
}
if (val1 == null) {
if (val2 != null) {
return false;
}
} else if (!val1.equals(val2)) {
return false;
}
}
return true;
}
作为一个通用的架构点,我通常建议不要让对特定序列化格式的依赖超出您的存储/网络层;因此,我首先建议您考虑测试您自己的应用程序对象之间的相等性,而不是它们的JSON表示。
话已这么说,我目前是Jackson的忠实粉丝,我快速阅读了他们的ObjectNode.equals()实现,建议进行你想要的集合成员比较:
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;
}
ModelAssert - https://github.com/webcompere/model-assert可以做到这一点。默认情况下,它更喜欢JSON是有序的,但它可以使用对象键和数组元素的宽松顺序:
assertJson(json1)
.where().keysInAnyOrder().arrayInAnyOrder()
.isEqualTo(json2);
这个断言是AssertJ风格的——即使用流畅的DSL。ModelAssert还可以用于使用相同的DSL构建Hamcrest或Mockito匹配器。
Json可以是字符串、文件、Jackson JsonNode,甚至是自发转换为Json进行比较的POJO。
还支持yml。
对于像我这样想要使用Jackson的人,您可以使用json-unit。
JsonAssert.assertJsonEquals(jsonNode1, jsonNode2);
错误给出了关于不匹配类型的有用反馈:
java.lang.AssertionError: JSON documents have different values:
Different value found in node "heading.content[0].tag[0]". Expected 10209, got 10206.