Java Jackson实现两JSON对比 填充首个对象null字段为第二对象非空值
可行性说明
该需求可直接通过Jackson原生JsonNode能力实现,无需引入额外依赖。核心规则为:仅对第一个JSON(目标对象)中缺失、或值为null的字段,用第二个JSON(源对象)的同名字段非空值填充,全程不覆盖目标对象已有的非空字段值。
实现逻辑
核心采用递归遍历处理,规则如下:
- 遍历源对象的所有字段,跳过源对象中值为
null的字段 - 对每个源字段,检查目标对象的同名字段:
- 目标无该字段、或字段值为
null:将源字段的深拷贝值写入目标 - 目标同名字段为非空对象、源字段也为对象类型:递归进入两个对象做深层字段合并
- 目标同名字段为非空的基本类型、数组类型:直接保留目标原有值,不做任何覆盖
- 目标无该字段、或字段值为
代码实现
首先引入Jackson核心依赖(如果你项目中已经引入jackson-databind可跳过),然后编写合并工具类:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.Iterator; import java.util.Map; public class JsonMergeUtils { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); /** * 非覆盖式JSON合并:仅填充目标对象缺失/值为null的字段,不覆盖已有非空值 * @param target 待补全的目标JSON对象(即第一个JSON) * @param source 提供补全字段的源JSON对象(即第二个JSON) * @return 合并完成的目标JSON对象 */ public static ObjectNode mergeNullAbsentFields(ObjectNode target, ObjectNode source) { Iterator<Map.Entry<String, JsonNode>> sourceFields = source.fields(); while (sourceFields.hasNext()) { Map.Entry<String, JsonNode> entry = sourceFields.next(); String fieldName = entry.getKey(); JsonNode sourceValue = entry.getValue(); // 源字段本身为null,无填充价值直接跳过 if (sourceValue.isNull()) { continue; } JsonNode targetValue = target.get(fieldName); if (targetValue == null || targetValue.isNull()) { // 目标字段缺失或为null,写入源字段的深拷贝避免引用关联 target.set(fieldName, sourceValue.deepCopy()); } else if (targetValue.isObject() && sourceValue.isObject()) { // 双方都是非空对象,递归做深层合并 mergeNullAbsentFields((ObjectNode) targetValue, (ObjectNode) sourceValue); } // 其余场景(目标为非空数组、基本类型):保留原值不处理 } return target; } // 测试方法 public static void main(String[] args) throws Exception { // 测试用例1:第一个JSON为缺失additionalInfo的形式一 String json1Form1 = "{\n" + " \"name\": \"test_name\",\n" + " \"contact\": [\n" + " {\"street\": \"st.1\", \"phoneNumber\": \"test_n\"}\n" + " ]\n" + "}"; // 测试用例2:第一个JSON为additionalInfo为null的形式二 String json1Form2 = "{\n" + " \"name\": \"test_name\",\n" + " \"contact\": [\n" + " {\"street\": \"st.1\", \"phoneNumber\": \"test_n\"}\n" + " ],\n" + " \"additionalInfo\": null\n" + "}"; String json2 = "{\n" + " \"name\": \"test_name_2\",\n" + " \"additionalInfo\": {\"lastName\": \"ln\", \"age\": 24}\n" + "}"; ObjectNode target = (ObjectNode) OBJECT_MAPPER.readTree(json1Form1); ObjectNode source = (ObjectNode) OBJECT_MAPPER.readTree(json2); ObjectNode result = mergeNullAbsentFields(target, source); // 打印格式化结果 System.out.println(OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(result)); } }
运行结果
两种形式的第一个JSON执行后,输出均完全符合预期:
{ "name" : "test_name", "contact" : [ { "street" : "st.1", "phoneNumber" : "test_n" } ], "additionalInfo" : { "lastName" : "ln", "age" : 24 } }
扩展说明
- 上述实现默认不处理数组内部元素的合并,如果需要对数组内对象按相同规则补全字段,可以在判断分支中增加数组节点的遍历合并逻辑
- 写入值时调用
deepCopy()是为了切断源和目标的节点引用关联,避免后续修改任意一方节点时产生意外联动 - 如果需要忽略字段大小写、自定义特殊字段合并规则,可以在遍历字段时增加对应的判断逻辑即可。
内容的提问来源于stack exchange,提问作者Disteonne
相关产品推荐
相关产品推荐

