You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:01:01