news 2026/9/3 3:44:24

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/9/3 2:23:21

终极实时视频抠图神器:RobustVideoMatting完整使用指南

终极实时视频抠图神器&#xff1a;RobustVideoMatting完整使用指南 【免费下载链接】RobustVideoMatting Robust Video Matting in PyTorch, TensorFlow, TensorFlow.js, ONNX, CoreML! 项目地址: https://gitcode.com/gh_mirrors/ro/RobustVideoMatting 想要在视频会议…

作者头像 李华
网站建设 2026/9/2 15:24:34

重新定义LaTeX排版体验:TinyTeX轻量级安装与实战指南

重新定义LaTeX排版体验&#xff1a;TinyTeX轻量级安装与实战指南 【免费下载链接】tinytex A lightweight, cross-platform, portable, and easy-to-maintain LaTeX distribution based on TeX Live 项目地址: https://gitcode.com/gh_mirrors/ti/tinytex 想要摆脱臃肿的…

作者头像 李华
网站建设 2026/9/2 6:54:52

ResNet-18实战指南:解决图像分类中的三大核心痛点

ResNet-18实战指南&#xff1a;解决图像分类中的三大核心痛点 【免费下载链接】resnet-18 项目地址: https://ai.gitcode.com/hf_mirrors/microsoft/resnet-18 你是否在为图像分类项目的落地而苦恼&#xff1f;模型太大部署困难&#xff1f;训练时间太长成本过高&#…

作者头像 李华
网站建设 2026/9/3 2:22:50

仓颉编程语言:开启智能开发新时代

仓颉编程语言&#xff1a;开启智能开发新时代 【免费下载链接】CangjieCommunity 为仓颉编程语言开发者打造活跃、开放、高质量的社区环境 项目地址: https://gitcode.com/Cangjie/CangjieCommunity 仓颉编程语言作为面向全场景智能的新一代编程语言&#xff0c;凭借其原…

作者头像 李华
网站建设 2026/9/3 0:50:14

CL4R1T4S项目:揭秘AI系统指令透明化的技术实践

CL4R1T4S项目&#xff1a;揭秘AI系统指令透明化的技术实践 【免费下载链接】CL4R1T4S SYSTEM INSTRUCTION TRANSPARENCY FOR ALL 项目地址: https://gitcode.com/gh_mirrors/cl/CL4R1T4S 你有没有想过&#xff0c;当你与ChatGPT、Claude或Gemini对话时&#xff0c;这些A…

作者头像 李华
网站建设 2026/9/2 3:45:24

从MAE到C-Eval(2)

从MAE到C-Eval&#xff08;1&#xff09; 这个系列好久没更了&#xff0c;当时停更是因为没有阅读量&#xff0c;但是我现在其实也不为了阅读量了&#xff0c;愿意写啥&#xff0c;写啥&#xff0c;所以就把这个系列又捡起来了&#xff08;我之前留的所有坑&#xff0c;每个系…

作者头像 李华