Java中两种json diff的实现学习

Posted FserSuN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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<String, Object>,随后通过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中两种json diff的实现学习的主要内容,如果未能解决你的问题,请参考以下文章

java中两种占位符的使用方式

Java语言中两种异常的差别

Java中两种获取Stream流的方式

Java|Java中两种抛出异常的方式

通过简单案例-深入理解深度学习中两种常用的归一化方法

如何解决线程不安全问题以及java中两种加锁