首页 > 解决方案 > 将两个没有值的 json 响应与 Jackson 进行比较

问题描述

是否可以将两个 json 响应与 Jackson lib 忽略所有值进行比较。

所以下面将断言属性和值。

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

代码:

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

标签: javajackson

解决方案


快速查找并没有产生任何结果,杰克逊为此功能内置了功能。但是,我们可以为此任务编写自己的检查器来比较两个Map<String, ?>s,从而返回true iff

  • 两个skeySet()相等Map
  • 属于两个s的keySet()那些对象的 是相等的instanceof MapMap
  • s的值Map在结构上也必须相同(递归调用)

对于分析,我们必须假设如果 aMap是 another 中的值Map,则它必须是 a,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());
}

Ideone demo

请注意,此解决方案不会验证密钥的类型是否相同。此外,如果一个键的值设置为null一个Map,而另一个键不存在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());
}

Ideone demo


推荐阅读