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的实现学习的主要内容,如果未能解决你的问题,请参考以下文章