news 2026/8/28 14:56:44

Java 三方 JSON 比对

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 三方 JSON 比对

在工作中遇到需要对前后两组数据进行比对,并返回比对结果,最终决定使用json进行比对,下面是几种方案。

核心工具对比

1. JSONassert(测试场景首选)

JSONassert 是专为测试设计的 JSON 比对工具,支持 忽略字段顺序、数组顺序、数值精度 等宽松模式,差异会以异常形式抛出,包含具体路径和值的对比。

步骤 1:引入依赖(Maven)

<dependency><groupId>org.skyscreamer</groupId><artifactId>jsonassert</artifactId><version>1.5.1</version><scope>test</scope><!--测试场景建议test scope--></dependency>

步骤 2:实操示例(比对差异并输出)

importorg.skyscreamer.jsonassert.JSONAssert;importorg.skyscreamer.jsonassert.JSONCompareMode;publicclassJsonAssertDemo{publicstaticvoidmain(String[]args){// 待比对的两个JSON字符串(结构相同,值有差异)StringexpectedJson="{\"name\":\"张三\",\"age\":20,\"address\":{\"city\":\"北京\"},\"hobbies\":[\"篮球\",\"游泳\"]}";StringactualJson="{\"name\":\"李四\",\"age\":20,\"address\":{\"city\":\"上海\"},\"hobbies\":[\"篮球\",\"跑步\"]}";try{// 严格模式(字段顺序、数组顺序、值完全一致才通过)JSONAssert.assertEquals(expectedJson,actualJson,JSONCompareMode.STRICT);}catch(AssertionErrore){// 捕获差异并输出System.out.println("JSON差异:\n"+e.getMessage());}}}

输出结果(精准定位差异)

JSON差异:Expected:"张三"got:"李四"at path $["name"]Expected:"北京"got:"上海"at path $["address"]["city"]Expected:"游泳"got:"跑步"at path $["hobbies"][1]

关键配置(JSONCompareMode)

  • STRICT:严格模式(字段顺序、数组顺序、值必须完全一致)
  • LENIENT:宽松模式(忽略字段顺序,数组顺序仍校验)
  • NON_EXTENSIBLE:不允许实际 JSON 包含预期外的字段
  • IGNORE_ARRAY_ORDER:忽略数组元素顺序
  • IGNORE_VALUES:只校验结构,忽略值的差异

2. JsonUnit(更友好的测试 API)

JsonUnit 基于 JSONassert 和 Jackson 封装,API 更简洁,差异输出更易读,支持 assertThat 风格的断言(符合 BDD 测试习惯)。

步骤 1:引入依赖

<dependency><groupId>net.javacrumbs.json-unit</groupId><artifactId>json-unit-core</artifactId><version>2.38.0</version><scope>test</scope></dependency><!--依赖JacksonJsonUnit底层用Jackson解析)--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency>

步骤 2:实操示例

importstaticnet.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;publicclassJsonUnitDemo{publicstaticvoidmain(String[]args){StringexpectedJson="{\"name\":\"张三\",\"age\":20,\"address\":{\"city\":\"北京\"}}";StringactualJson="{\"name\":\"李四\",\"age\":21,\"address\":{\"city\":\"北京\"}}";// 比对并输出差异(AssertJ风格)assertThatJson(actualJson).isEqualTo(expectedJson).onFailure(failure->System.out.println("JSON差异:\n"+failure.getMessage()));}}

输出结果

JSON差异:Expectedvalue<"张三">but was<"李四">at path $['name']Expectedvalue<20>but was<21>at path $['age']

高级用法(忽略指定字段)

// 忽略age字段的差异assertThatJson(actualJson).whenIgnoringPaths("age").isEqualTo(expectedJson);

3. Jackson(业务开发灵活定制)

Jackson 是 Java 最主流的 JSON 处理库,通过 JsonNode 树模型可完全自定义比对逻辑(适合业务开发中需要精细控制差异的场景)。

步骤 1:引入依赖

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency>

步骤 2:自定义比对工具类(输出差异路径和值)

importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importjava.util.ArrayList;importjava.util.List;publicclassJacksonJsonDiff{privatestaticfinalObjectMapperOBJECT_MAPPER=newObjectMapper();privatestaticfinalList<String>DIFFS=newArrayList<>();// 比对两个JSON字符串,返回差异列表publicstaticList<String>compareJson(StringexpectedJson,StringactualJson)throwsException{DIFFS.clear();JsonNodeexpectedNode=OBJECT_MAPPER.readTree(expectedJson);JsonNodeactualNode=OBJECT_MAPPER.readTree(actualJson);compareNodes("",expectedNode,actualNode);returnDIFFS;}// 递归比对JsonNode节点privatestaticvoidcompareNodes(Stringpath,JsonNodeexpected,JsonNodeactual){// 节点类型不同if(expected.getNodeType()!=actual.getNodeType()){DIFFS.add(path+":类型不一致(预期:"+expected.getNodeType()+",实际:"+actual.getNodeType()+")");return;}// 叶子节点(值节点)if(expected.isValueNode()){if(!expected.equals(actual)){DIFFS.add(path+":值不一致(预期:"+expected.asText()+",实际:"+actual.asText()+")");}return;}// 对象节点(递归比对子字段)if(expected.isObject()){expected.fieldNames().forEachRemaining(fieldName->{StringnewPath=path.isEmpty()?"$."+fieldName:path+"."+fieldName;JsonNodeexpectedChild=expected.get(fieldName);JsonNodeactualChild=actual.get(fieldName);if(actualChild==null){DIFFS.add(newPath+":实际JSON缺失该字段");}else{compareNodes(newPath,expectedChild,actualChild);}});// 检查实际JSON是否有预期外的字段actual.fieldNames().forEachRemaining(fieldName->{if(!expected.has(fieldName)){StringnewPath=path.isEmpty()?"$."+fieldName:path+"."+fieldName;DIFFS.add(newPath+":实际JSON包含预期外的字段");}});}// 数组节点(递归比对数组元素)if(expected.isArray()){intexpectedSize=expected.size();intactualSize=actual.size();if(expectedSize!=actualSize){DIFFS.add(path+":数组长度不一致(预期:"+expectedSize+",实际:"+actualSize+")");}// 比对数组元素(按索引)intmaxSize=Math.max(expectedSize,actualSize);for(inti=0;i<maxSize;i++){StringnewPath=path+"["+i+"]";JsonNodeexpectedChild=i<expectedSize?expected.get(i):null;JsonNodeactualChild=i<actualSize?actual.get(i):null;if(expectedChild==null){DIFFS.add(newPath+":实际数组多出元素");}elseif(actualChild==null){DIFFS.add(newPath+":实际数组缺失元素");}else{compareNodes(newPath,expectedChild,actualChild);}}}}// 测试publicstaticvoidmain(String[]args)throwsException{StringexpectedJson="{\"name\":\"张三\",\"age\":20,\"address\":{\"city\":\"北京\"},\"hobbies\":[\"篮球\",\"游泳\"]}";StringactualJson="{\"name\":\"李四\",\"age\":20,\"address\":{\"city\":\"上海\"},\"hobbies\":[\"篮球\",\"跑步\"]}";List<String>diffs=compareJson(expectedJson,actualJson);System.out.println("JSON差异列表:");diffs.forEach(diff->System.out.println("- "+diff));}}

输出结果

JSON差异列表:-$.name:值不一致(预期:张三,实际:李四)-$.address.city:值不一致(预期:北京,实际:上海)-$.hobbies[1]:值不一致(预期:游泳,实际:跑步)

4. Diffuse(轻量级结构化差异输出)

Diffuse 是轻量级工具,可输出 JSON 格式的结构化差异报告(包含添加 / 修改 / 删除的节点),适合需要将差异持久化或传输的场景。

步骤 1:引入依赖

<dependency><groupId>me.snov</groupId><artifactId>diffuse</artifactId><version>0.2.0</version></dependency>

步骤 2:实操示例

importme.snov.diffuse.Diffuse;importme.snov.diffuse.JsonDiff;publicclassDiffuseDemo{publicstaticvoidmain(String[]args){StringexpectedJson="{\"name\":\"张三\",\"age\":20}";StringactualJson="{\"name\":\"李四\",\"age\":21,\"gender\":\"男\"}";// 生成结构化差异报告JsonDiffdiff=Diffuse.diff(expectedJson,actualJson);System.out.println("结构化差异报告:\n"+diff.toJson());}}

输出结果(JSON 格式)

{"changed":[{"path":"/name","from":"张三","to":"李四"},{"path":"/age","from":20,"to":21}],"added":[{"path":"/gender","value":"男"}],"removed":[]}

选型建议

  1. 测试场景:优先选 JsonUnit(API 友好)或 JSONassert(轻量);
  2. 业务开发:优先选 Jackson(灵活自定义比对规则);
  3. 需要结构化差异输出:选 Diffuse;
  4. 特殊需求(如忽略数值精度、时间格式):基于 Jackson 扩展自定义比对逻辑。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/26 18:34:29

OpCore Simplify强力解决方案:零基础快速搭建完美黑苹果系统

OpCore Simplify强力解决方案&#xff1a;零基础快速搭建完美黑苹果系统 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为复杂的OpenCore配置而苦…

作者头像 李华
网站建设 2026/8/28 8:22:43

黑苹果配置新纪元:智能工具OpCore-Simplify完全指南

黑苹果配置新纪元&#xff1a;智能工具OpCore-Simplify完全指南 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 在传统黑苹果配置中&#xff0c;用户需…

作者头像 李华
网站建设 2026/8/22 10:11:50

123云盘免费解锁指南:轻松突破限制享受完整会员体验

还在为123云盘的各种限制而烦恼吗&#xff1f;下载速度缓慢、广告弹窗不断、高级功能无法使用...这些问题现在都可以通过一个简单易用的解锁方案轻松解决。本文将为你深度解析123云盘解锁的核心原理和实际效果&#xff0c;让你无需付费即可享受超级会员的完整体验。 【免费下载…

作者头像 李华
网站建设 2026/8/24 14:15:07

无人机三维建模神器Pix4D Mapper:从零开始快速上手完整指南

无人机三维建模神器Pix4D Mapper&#xff1a;从零开始快速上手完整指南 【免费下载链接】UAVPix4DMapper介绍与安装包 Pix4D Mapper是一款专业的无人机&#xff08;UAV&#xff09;数据处理软件&#xff0c;广泛应用于地理信息系统&#xff08;GIS&#xff09;、农业、建筑和环…

作者头像 李华
网站建设 2026/8/20 18:44:55

如何5分钟完成智能配置:OpCore-Simplify新手快速上手指南

如何5分钟完成智能配置&#xff1a;OpCore-Simplify新手快速上手指南 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为复杂的OpenCore配置而头疼…

作者头像 李华
网站建设 2026/8/25 13:15:35

123云盘VIP功能完全解锁教程:免费享受超级会员特权

还在为123云盘的下载限制和广告干扰而困扰吗&#xff1f;今天我将为你介绍一个简单实用的解决方案——123云盘解锁脚本。这个基于用户脚本的工具能够让你免费享受123云盘的所有会员功能&#xff0c;包括高速下载、无广告体验和个性化设置。无论你是新手还是资深用户&#xff0c…

作者头像 李华