Java中两种json diff的实现学习

Java中两种json diff的实现学习

json diff就是找两个json的差异,找差异时维度可以是第一层字段维度。或者是深度差异比较。

为了演示这个功能,需要依赖两个工具包。

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.0-jre</version>
        </dependency>
        
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.1</version>
        </dependency>

演示使用的两个样例JSON如下:

    private String listN1 = "{\n" +
            "    \"employee\":\n" +
            "    {\n" +
            "        \"id\": \"1212\",\n" +
            "        \"fullName\": \"John Miles\",\n" +
            "        \"age\": 34,\n" +
            "        \"skills\": [\"C+++\", \"Java\", \"Python\"]\n" +
            "    }\n" +
            "}";

    private String listN2 = "{\n" +
            "    \"employee\":\n" +
            "    {\n" +
            "        \"id\": \"1212\",\n" +
            "        \"age\": 34,\n" +
            "        \"fullName\": \"John Miles\",\n" +
            "        \"skills\": [\"Java\", \"C++\", \"Python\"] \n" +
            "    } \n" +
            "}";

第一层字段维度的json diff : 通过jackson json工具读入json字符串,并将其转换为HashMap,随后通过Guava工具包中的Maps.difference实现diff比较。这种方式比较简单,但也只能检测到第一层字段上的变化,因此略显粗糙。但如果只关注第一层字段上的变化,那么使用这个方式还是很方便。

    @Test
    public void testJsonDiffOnField() throws Exception{
        ObjectMapper mapper = new ObjectMapper();

        TypeReference<HashMap<String, Object>> type =
                new TypeReference<HashMap<String, Object>>() {};

        HashMap<String, Object> j1 = mapper.readValue(listN1,type);
        HashMap<String, Object> j2 = mapper.readValue(listN2,type);

        MapDifference<String,Object> difference = Maps.difference(j1,j2);
    }

深度比较:深度比较的思路是先将json平铺,随后再通过Maps.difference找出变化即可。因此这种方式需要用到一个平铺工具。

工具的核心思路就是递归的进行flat(平铺)操作,直到元素不再是集合类型。下面是flat(平铺)工具实现代码。

public class FlatMapUtil {
    private FlatMapUtil() {
        throw new AssertionError("No instances for you!");
    }

    public static Map<String, Object> flatten(Map<String, Object> map) {
        return map.entrySet().stream()
                .flatMap(FlatMapUtil::flatten)
                .collect(LinkedHashMap::new, (m, e) -> m.put("/" + e.getKey(), e.getValue()), LinkedHashMap::putAll);
    }

    private static Stream<Map.Entry<String, Object>> flatten(Map.Entry<String, Object> entry) {

        if (entry == null) {
            return Stream.empty();
        }

        if (entry.getValue() instanceof Map<?, ?>) {
            return ((Map<?, ?>) entry.getValue()).entrySet().stream()
                    .flatMap(e -> flatten(new AbstractMap.SimpleEntry<>(entry.getKey() + "/" + e.getKey(), e.getValue())));
        }

        if (entry.getValue() instanceof List<?>) {
            List<?> list = (List<?>) entry.getValue();
            return IntStream.range(0, list.size())
                    .mapToObj(i -> new AbstractMap.SimpleEntry<String, Object>(entry.getKey() + "/" + i, list.get(i)))
                    .flatMap(FlatMapUtil::flatten);
        }

        return Stream.of(entry);
    }
}

最后再通过Maps.difference找出差异即可。


    @Test
    public void testJsonDiffByFlatten() throws Exception{
        ObjectMapper mapper = new ObjectMapper();

        TypeReference<HashMap<String, Object>> type =
                new TypeReference<HashMap<String, Object>>() {};


        HashMap<String, Object> j1 = mapper.readValue(listN1,type);
        HashMap<String, Object> j2 = mapper.readValue(listN2,type);

        Map<String, Object> flatten1 = FlatMapUtil.flatten(j1);
        Map<String, Object> flatten2 = FlatMapUtil.flatten(j2);
        MapDifference<String,Object> difference = Maps.difference(flatten1,flatten2);
    }

比较

  • 平铺化:该方式能更精确的找出差异变化,但有些场景下,发现差异后对差异需要操作,这种方式还需要额外完成一些功能。
  • 第一层字段维度:思路简单,不够精细,但在某些具体场景下更简洁。

其它实现

此外还可以通过第三方工具实现,比如下面的工具。具体使用可查看官方文档。

<!-- Java API for JSON Processing (API) -->
<dependency>
    <groupId>javax.json</groupId>
    <artifactId>javax.json-api</artifactId>
    <version>1.1.2</version>
</dependency>

<!-- Java API for JSON Processing (implementation) -->
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1.2</version>
</dependency>

参考

[1] 比较两个json,https://www.baeldung.com/jackson-compare-two-json-objects

你可能感兴趣的:(Java)