使用Jackson比较两个不带值的JSON响应。

huangapple go评论59阅读模式
英文:

Compare two json responses without values with Jackson

问题

这是否可能使用Jackson库比较两个JSON响应,忽略所有值。

因此,以下将断言属性和值。

{
    "employee":
    {
        "id": "1212",
        "fullName": "John Miles",
        "age": 34
    }
}

代码:

ObjectMapper mapper = new ObjectMapper();
assertEquals(mapper.readTree(s1), mapper.readTree(s2));
英文:

Is that possible to compare two json responses with Jackson lib ignoring all values.

So below will assert both attribute and values.

{
    "employee":
    {
        "id": "1212",
        "fullName": "John Miles",
        "age": 34
    }
}

Code:

ObjectMapper mapper = new ObjectMapper();
assertEquals(mapper.readTree(s1), mapper.readTree(s2));

答案1

得分: 1

以下是翻译好的内容:

一个快速查找没有产生任何结果,说明 Jackson 没有内置此功能的能力。然而,我们可以为这个任务编写自己的检查器,以比较两个 Map<String, ?>,并以这样的方式返回 true 当且仅当

  • 两个 MapkeySet() 相等。
  • 那些是两个 Mapinstanceof Map 的对象的 keySet() 相等。
  • 那些是 Map 值的值也必须在结构上相等(递归调用)。

对于分析,我们必须假设如果一个 Map 是另一个 Map 中的值,它必须是 Map<String, ?>,因为我们的解决方案将在此假设下进行未检查的转换。

在这个假设的基础上,解决方案可能如下所示:

@SuppressWarnings("unhecked")
public static boolean areStructuralEqual(Map<String, ?> left, Map<String, ?> right) {
    if (!Objects.equals(left.keySet(), right.keySet())) {
        return false;
    }

    Set<String> leftKeysWithMapValues = extractAllKeysThatMapToMaps(left);
    Set<String> rightKeysWithMapValues = extractAllKeysThatMapToMaps(right);
    if (!Objects.equals(leftKeysWithMapValues, rightKeysWithMapValues)) {
        return false;
    }

    for (String key : leftKeysWithMapValues) {
        if (!areStructuralEqual(
                (Map<String, ?>) left.get(key),
                (Map<String, ?>) right.get(key))) {
            return false;
        }
    }
    return true;
}

private static Set<String> extractAllKeysThatMapToMaps(Map<String, ?> map) {
    return map.entrySet().stream()
            .filter(e -> e.getValue() instanceof Map)
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
}

请注意,此解决方案不会验证键的类型是否相同。此外,如果一个 Map 的值在另一个 Map 中设置为 null,而在另一个 Map 中不存在该键,则比较将返回 false。后者可以通过过滤值为 null 的键来修复:

@SuppressWarnings("unhecked")
public static boolean areStructuralEqual(Map<String, ?> left, Map<String, ?> right) {
    Set<Entry<String, ?>> leftEntriesWithNonNullValues = 
            extractEntriesWithNonNullValues(left);
    Set<Entry<String, ?>> rightEntriesWithNonNullValues =
            extractEntriesWithNonNullValues(right);
    Set<String> leftKeysWithNonNullValues = leftEntriesWithNonNullValues.stream()
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
    Set<String> rightKeysWithNonNullValues = rightEntriesWithNonNullValues.stream()
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
    if (!Objects.equals(leftKeysWithNonNullValues, rightKeysWithNonNullValues)) {
        return false;
    }

    Set<String> leftKeysWithMapValues =
            extractAllKeysThatMapToMaps(leftEntriesWithNonNullValues);
    Set<String> rightKeysWithMapValues =
            extractAllKeysThatMapToMaps(rightEntriesWithNonNullValues);
    if (!Objects.equals(leftKeysWithMapValues, rightKeysWithMapValues)) {
        return false;
    }

    for (String key : leftKeysWithMapValues) {
        if (!areStructuralEqual(
                (Map<String, ?>) left.get(key),
                (Map<String, ?>) right.get(key))) {
            return false;
        }
    }
    return true;
}

private static Set<String> extractAllKeysThatMapToMaps(Set<Entry<String, ?>> entrySet) {
    return entrySet.stream()
            .filter(e -> e.getValue() instanceof Map)
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
}

private static Set<Entry<String, ?>> extractEntriesWithNonNullValues(Map<String, ?> map) {
    return map.entrySet().stream()
            .filter(e -> Objects.nonNull(e.getValue()))
            .collect(Collectors.toUnmodifiableSet());
}

<kbd>Ideone 演示</kbd>

请注意,此解决方案不会验证键的类型是否相同。此外,如果一个 Map 的值在另一个 Map 中设置为 null,而在另一个 Map 中不存在该键,则比较将返回 false。后者可以通过过滤值为 null 的键来修复:

@SuppressWarnings("unhecked")
public static boolean areStructuralEqual(Map<String, ?> left, Map<String, ?> right) {
    Set<Entry<String, ?>> leftEntriesWithNonNullValues = 
            extractEntriesWithNonNullValues(left);
    Set<Entry<String, ?>> rightEntriesWithNonNullValues =
            extractEntriesWithNonNullValues(right);
    Set<String> leftKeysWithNonNullValues = leftEntriesWithNonNullValues.stream()
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
    Set<String> rightKeysWithNonNullValues = rightEntriesWithNonNullValues.stream()
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
    if (!Objects.equals(leftKeysWithNonNullValues, rightKeysWithNonNullValues)) {
        return false;
    }

    Set<String> leftKeysWithMapValues =
            extractAllKeysThatMapToMaps(leftEntriesWithNonNullValues);
    Set<String> rightKeysWithMapValues =
            extractAllKeysThatMapToMaps(rightEntriesWithNonNullValues);
    if (!Objects.equals(leftKeysWithMapValues, rightKeysWithMapValues)) {
        return false;
    }

    for (String key : leftKeysWithMapValues) {
        if (!areStructuralEqual(
                (Map<String, ?>) left.get(key),
                (Map<String, ?>) right.get(key))) {
            return false;
        }
    }
    return true;
}

private static Set<String> extractAllKeysThatMapToMaps(Set<Entry<String, ?>> entrySet) {
    return entrySet.stream()
            .filter(e -> e.getValue() instanceof Map)
            .map(Entry::getKey)
            .collect(Collectors.toUnmodifiableSet());
}

private static Set<Entry<String, ?>> extractEntriesWithNonNullValues(Map<String, ?> map) {
    return map.entrySet().stream()
            .filter(e -> Objects.nonNull(e.getValue()))
            .collect(Collectors.toUnmodifiableSet());
}

<kbd>Ideone 演示</kbd>

英文:

A quick lookup did not yield any results that Jackson has built-in capabilites for this functionality. We can, however, write our own checker for this task to compare two Map&lt;String, ?&gt;s in such a way that we return true iff.:

  • the keySet() of both Maps are equal
  • the keySet() of those objects that are instanceof Map of both Maps are equal
  • the values which are Maps must be structurally equally aswell (recursive call)

For the analysis, we have to make the assumption that if a Map is a value in another Map, it must be a Map&lt;String, ?&gt; since our solution will make an unchecked cast with this assumption.

With this assumption, a solution may look like this:

@SuppressWarnings(&quot;unhecked&quot;)
public static boolean areStructuralEqual(Map&lt;String, ?&gt; left, Map&lt;String, ?&gt; right) {
if (!Objects.equals(left.keySet(), right.keySet())) {
return false;
}
Set&lt;String&gt; leftKeysWithMapValues = extractAllKeysThatMapToMaps(left);
Set&lt;String&gt; rightKeysWithMapValues = extractAllKeysThatMapToMaps(right);
if (!Objects.equals(leftKeysWithMapValues, rightKeysWithMapValues)) {
return false;
}
for (String key : leftKeysWithMapValues) {
if (!areStructuralEqual(
(Map&lt;String, ?&gt;) left.get(key),
(Map&lt;String, ?&gt;) right.get(key))) {
return false;
}
}
return true;
}
private static Set&lt;String&gt; extractAllKeysThatMapToMaps(Map&lt;String, ?&gt; map) {
return map.entrySet().stream()
.filter(e -&gt; e.getValue() instanceof Map)
.map(Entry::getKey)
.collect(Collectors.toUnmodifiableSet());
}

<kbd>Ideone demo</kbd>

Notice that this solution does not verify that the types of the keys are the same. Also, if the value of a key is set to null in one Map and the key is not present in the other Map, the comparison will return false. The latter can be fixed by filtering out keys whose values are null:

@SuppressWarnings(&quot;unhecked&quot;)
public static boolean areStructuralEqual(Map&lt;String, ?&gt; left, Map&lt;String, ?&gt; right) {
Set&lt;Entry&lt;String, ?&gt;&gt; leftEntriesWithNonNullValues = 
extractEntriesWithNonNullValues(left);
Set&lt;Entry&lt;String, ?&gt;&gt; rightEntriesWithNonNullValues =
extractEntriesWithNonNullValues(right);
Set&lt;String&gt; leftKeysWithNonNullValues = leftEntriesWithNonNullValues.stream()
.map(Entry::getKey)
.collect(Collectors.toUnmodifiableSet());
Set&lt;String&gt; rightKeysWithNonNullValues = rightEntriesWithNonNullValues.stream()
.map(Entry::getKey)
.collect(Collectors.toUnmodifiableSet());
if (!Objects.equals(leftKeysWithNonNullValues, rightKeysWithNonNullValues)) {
return false;
}
Set&lt;String&gt; leftKeysWithMapValues =
extractAllKeysThatMapToMaps(leftEntriesWithNonNullValues);
Set&lt;String&gt; rightKeysWithMapValues =
extractAllKeysThatMapToMaps(rightEntriesWithNonNullValues);
if (!Objects.equals(leftKeysWithMapValues, rightKeysWithMapValues)) {
return false;
}
for (String key : leftKeysWithMapValues) {
if (!areStructuralEqual(
(Map&lt;String, ?&gt;) left.get(key),
(Map&lt;String, ?&gt;) right.get(key))) {
return false;
}
}
return true;
}
private static Set&lt;String&gt; extractAllKeysThatMapToMaps(Set&lt;Entry&lt;String, ?&gt;&gt; entrySet) {
return entrySet.stream()
.filter(e -&gt; e.getValue() instanceof Map)
.map(Entry::getKey)
.collect(Collectors.toUnmodifiableSet());
}
private static Set&lt;Entry&lt;String, ?&gt;&gt; extractEntriesWithNonNullValues(Map&lt;String, ?&gt; map) {
return map.entrySet().stream()
.filter(e -&gt; Objects.nonNull(e.getValue()))
.collect(Collectors.toUnmodifiableSet());
}

<kbd>Ideone demo</kbd>

huangapple
  • 本文由 发表于 2020年8月24日 06:47:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/63552747.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定