Java中如何局部更新JSONObject且不丢失原有字段?
如何深度更新JSONObject而不丢失原有字段
要实现仅用部分JSON更新原JSONObject且保留未涉及字段,核心是递归遍历并合并层级结构:遇到嵌套对象时递归合并,遇到数组、基本类型(字符串/数字/布尔)则直接替换。以下是两种主流语言的通用实现:
Python 实现
用字典模拟JSONObject,写一个递归深度更新函数:
def deep_update(original, update): for key, value in update.items(): # 如果当前更新值是字典,且原对象对应key也是字典,递归合并 if isinstance(value, dict) and key in original and isinstance(original[key], dict): deep_update(original[key], value) # 否则直接替换(数组、基本类型或原对象无此key的情况) else: original[key] = value return original
测试示例
# 原JSON转字典 original_json = { "title": "Lamp", "events": { "overheating": { "data": {"type": "string"}, "forms": [{"href": "https://www.lamp.com/oh", "subprotocol": "longpoll"}] } }, "actions": {"toggle": {"forms": [{"href": "https://lampione.it/toggle"}]}}, "@context": "https://www.w3.org/2019/wot/td/v1", "security": ["basic_sc"], "properties": {}, "securityDefinitions": {"basic_sc": {"in": "header", "scheme": "basic"}}, "id": "urn:uuid:8c426e18-f579-42b1-a3c9-7aa9c86fbacf" } # 更新部分转字典 update_json = { "events": { "overheating": { "forms": [{"href": "https://lampada.it/oh", "subprotocol": "longpoll"}] } } } # 执行更新 updated_json = deep_update(original_json, update_json) # 验证结果:events.overheating.data 被保留,forms 已更新 print(updated_json["events"]["overheating"]["data"]) # 输出: {'type': 'string'} print(updated_json["events"]["overheating"]["forms"][0]["href"]) # 输出: https://lampada.it/oh
Java 实现(基于Jackson)
利用Jackson的JsonNode和ObjectNode实现递归深度合并:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; public class JsonDeepUpdater { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static JsonNode deepUpdate(JsonNode originalNode, JsonNode updateNode) { // 仅处理对象类型的节点合并 if (originalNode.isObject() && updateNode.isObject()) { ObjectNode originalObj = (ObjectNode) originalNode; // 遍历更新节点的所有字段 updateNode.fields().forEachRemaining(entry -> { String key = entry.getKey(); JsonNode updateValue = entry.getValue(); // 若原节点有该key且都是对象,递归合并 if (originalObj.has(key) && originalObj.get(key).isObject() && updateValue.isObject()) { originalObj.set(key, deepUpdate(originalObj.get(key), updateValue)); } else { // 否则直接替换(数组、基本类型或新增字段) originalObj.set(key, updateValue); } }); return originalObj; } // 非对象类型直接返回更新值 return updateNode; } // 测试用例 public static void main(String[] args) throws Exception { String originalStr = "{\"title\":\"Lamp\",\"events\":{\"overheating\":{\"data\":{\"type\":\"string\"},\"forms\":[{\"href\":\"https://www.lamp.com/oh\",\"subprotocol\":\"longpoll\"}]}},\"actions\":{\"toggle\":{\"forms\":[{\"href\":\"https://lampione.it/toggle\"}]}},\"@context\":\"https://www.w3.org/2019/wot/td/v1\",\"security\":[\"basic_sc\"],\"properties\":{},\"securityDefinitions\":{\"basic_sc\":{\"in\":\"header\",\"scheme\":\"basic\"}},\"id\":\"urn:uuid:8c426e18-f579-42b1-a3c9-7aa9c86fbacf\"}"; String updateStr = "{\"events\":{\"overheating\":{\"forms\":[{\"href\":\"https://lampada.it/oh\",\"subprotocol\":\"longpoll\"}]}}}"; JsonNode original = OBJECT_MAPPER.readTree(originalStr); JsonNode update = OBJECT_MAPPER.readTree(updateStr); JsonNode updated = deepUpdate(original, update); // 验证结果 System.out.println(updated.get("events").get("overheating").get("data")); // 输出: {"type":"string"} System.out.println(updated.get("events").get("overheating").get("forms").get(0).get("href")); // 输出: "https://lampada.it/oh" } }
注意事项
- 数组处理:上述实现中数组会被直接替换,如果需要追加数组元素而非替换,需修改逻辑判断数组类型并做合并操作。
- 空值处理:若更新JSON中包含
null值,会直接覆盖原字段的非空值,若需跳过null更新,可在函数中增加判断逻辑。 - 新增字段:更新JSON中的新增字段会直接添加到原JSONObject中。
内容的提问来源于stack exchange,提问作者simonetassi
相关产品推荐
相关产品推荐

