如何避免ObjectMapper的readerForUpdating覆盖已有非空数据?
解决方案:仅更新原对象中为null的字段
默认情况下,readerForUpdating会用JSON中的值覆盖目标对象的所有对应字段,不管原字段是否为空。要实现仅更新原对象中为null的属性,可以通过以下两种可行方案解决:
方案一:手动属性拷贝(简单直接)
先将JSON反序列化为临时Record对象,再手动判断原对象的属性是否为null,仅替换空值字段:
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 将JSON转为临时对象 Record tempRecord = objectMapper.readValue(incomingJson, Record.class); // 仅更新原对象中为null的属性 if (record.getResource() == null) { record.setResource(tempRecord.getResource()); } // 若有更多字段,按相同逻辑依次判断处理
这种方法适合字段较少的场景,代码直观,无需额外配置。
方案二:自定义Jackson反序列化器(优雅通用)
通过自定义BeanDeserializerModifier修改默认反序列化行为,让它只更新原对象中为null的属性:
1. 实现自定义BeanDeserializer
import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.deser.BeanDeserializer; import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; import com.fasterxml.jackson.databind.deser.SettableBeanProperty; import com.fasterxml.jackson.databind.util.NameTransformer; import java.io.IOException; public class NullOnlyUpdateDeserializer extends BeanDeserializer { private final BeanDeserializer originalDeserializer; public NullOnlyUpdateDeserializer(BeanDeserializer original) { super(original); this.originalDeserializer = original; } @Override public Object deserialize(ObjectParser p, DeserializationContext ctxt) throws IOException { // 获取要更新的目标对象 Object target = ctxt.findInjectableValue("_valueToUpdate", null, null); if (target == null) { return super.deserialize(p, ctxt); } // 解析JSON到临时对象 Object temp = originalDeserializer.deserialize(p, ctxt); // 遍历属性,仅更新目标对象中的空值字段 for (SettableBeanProperty prop : _beanProperties) { try { Object targetValue = prop.get(target); if (targetValue == null) { Object tempValue = prop.get(temp); prop.set(target, tempValue); } } catch (Exception e) { throw new IOException("更新属性" + prop.getName() + "失败", e); } } return target; } @Override public JsonDeserializer<Object> unwrappingDeserializer(NameTransformer unwrapper) { return new NullOnlyUpdateDeserializer((BeanDeserializer) originalDeserializer.unwrappingDeserializer(unwrapper)); } }
2. 实现BeanDeserializerModifier
import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; public class NullOnlyUpdateModifier extends BeanDeserializerModifier { @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { if (deserializer instanceof BeanDeserializer) { return new NullOnlyUpdateDeserializer((BeanDeserializer) deserializer); } return super.modifyDeserializer(config, beanDesc, deserializer); } }
3. 配置ObjectMapper使用自定义Modifier
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 注册自定义反序列化修改器 objectMapper.registerModule(new SimpleModule() .setDeserializerModifier(new NullOnlyUpdateModifier())); // 执行更新操作 objectMapper.readerForUpdating(record).readValue(incomingJson);
配置完成后,readerForUpdating会仅更新原对象中为null的属性,非null属性保留原值,完全符合你的期望输出。
为什么@JsonMerge没生效?
@JsonMerge注解主要用于嵌套对象(如集合、复杂对象)的合并逻辑,而非控制“仅更新空值”的规则,因此单独使用无法实现你的需求,需要配合自定义反序列化逻辑或手动属性拷贝。
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

