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

如何让Jackson将显式null反序列化为Optional.EMPTY且不序列化空Optional为null

Jackson中Optional序列化与反序列化的冲突解决

问题背景

现有如下POJO类:

public static class Test {
  private Optional<String> something;
}

以及配置好的Jackson映射器:

var OBJECT_MAPPER = JsonMapper.builder()
  .addModule(new Jdk8Module())
  .serializationInclusion(JsonInclude.Include.NON_ABSENT)
  .build();

当前遇到的问题:

  • 反序列化JSON字符串{"something": null}时,得到的Test对象中something属性为null,但期望该值为Optional.EMPTY。
  • 期望的Optional反序列化规则:
    • JSON中属性值为null → 反序列化为Optional.EMPTY
    • JSON中未提供该属性 → POJO中属性保持null
    • JSON中属性为非null值 → 反序列化为Optional.of(对应值)

但如果移除serializationInclusion(JsonInclude.Include.NON_ABSENT)配置,虽然能满足反序列化需求,却会导致序列化不符合预期:

Test test = new Test();
// 期望序列化为{}, 而非{"something": null}

Test test2 = new Test();
test2.setSomething(Optional.EMPTY);
// 期望序列化为{}, 而非{"something": null}

需求核心:能否为序列化和反序列化分别设置serializationInclusion?

解决方案

Jackson本身不支持直接为序列化、反序列化单独配置serializationInclusion,但可以通过两种方式实现需求:

方式一:自定义Optional序列化器与反序列化器

通过定制序列化和反序列化逻辑,精准控制Optional的处理行为:

自定义序列化器

确保当Optional为null或Optional.EMPTY时,配合NON_ABSENT配置过滤掉该属性;非空Optional则输出实际值:

public class CustomOptionalSerializer extends StdSerializer<Optional<?>> {
    public CustomOptionalSerializer() {
        super(Optional.class);
    }

    @Override
    public void serialize(Optional<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (value == null || value.isEmpty()) {
            gen.writeNull(); // 会被NON_ABSENT配置过滤
        } else {
            gen.writeObject(value.get());
        }
    }
}

自定义反序列化器

将JSON中的null值转为Optional.EMPTY,非null值包装为Optional.of(),未提供属性则保留POJO属性为null:

public class CustomOptionalDeserializer extends StdDeserializer<Optional<?>> {
    public CustomOptionalDeserializer() {
        super(Optional.class);
    }

    @Override
    public Optional<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        if (node.isNull()) {
            return Optional.empty();
        }
        Object value = ctxt.readValue(p, ctxt.getContextualType().getContentType().getRawClass());
        return Optional.ofNullable(value);
    }
}

注册自定义组件到映射器

var OBJECT_MAPPER = JsonMapper.builder()
        .addModule(new Jdk8Module())
        .serializationInclusion(JsonInclude.Include.NON_ABSENT)
        .addSerializer(Optional.class, new CustomOptionalSerializer())
        .addDeserializer(Optional.class, new CustomOptionalDeserializer())
        .build();

方式二:使用两个独立的ObjectMapper

分别创建用于序列化和反序列化的映射器,各自配置所需规则:

// 序列化专用Mapper:保留NON_ABSENT配置,过滤空值属性
var SERIALIZE_MAPPER = JsonMapper.builder()
        .addModule(new Jdk8Module())
        .serializationInclusion(JsonInclude.Include.NON_ABSENT)
        .build();

// 反序列化专用Mapper:不设置序列化过滤规则,满足null转Optional.EMPTY的需求
var DESERIALIZE_MAPPER = JsonMapper.builder()
        .addModule(new Jdk8Module())
        .build();

使用时序列化调用SERIALIZE_MAPPER,反序列化调用DESERIALIZE_MAPPER即可。

内容的提问来源于stack exchange,提问作者k.liakos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:17:48