7

我想比较 Java 8 中的两个 JSON 字符串是否相等,但忽略特定的已知节点,这些节点包含预期不同的值并且是可以容忍的差异,例如时间戳。目前使用来自 org.SkyScreamer 的 JSONAssert v1.5.0,我能够“忽略”其中一些节点,但不能“忽略”数组中的节点。

我想要扩展我当前的 JSONComparator 以包含一个自定义,它的第一个“路径”参数具有一个数组地址。

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?
            );

下面的代码是我试图证明解决方案的尝试;除了 anArray[].id 值之外,预期/实际 JSON 字符串都是相同的。我希望此测试通过,但失败并出现错误:java.lang.AssertionError: anArray[0] 找不到元素 {"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);
}
4

2 回答 2

13

在对 JSONAssert的 javadoc 进行了一些挖掘之后,我看到了一个使用对象数组的示例。从该示例中,我能够修改您的测试用例:

    @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);
    }
于 2018-06-19T04:18:39.133 回答
2

根据我的要求,需要忽略businessCorrelationId仅存在一次的字段,effectiveStartDate存在于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
  }
}

下面的代码工作正常。

JSONAssert.assertEquals(expectedJson, actualJson, new CustomComparator(JSONCompareMode.LENIENT,
   new Customization("data[*].createdTimestamp", (ct1, ct2) -> true),
   new Customization("messageElements.businessCorrelationId", (c1, c2) -> true)));
于 2021-02-08T10:57:32.697 回答