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

Spring Boot中Jackson实现Optional属性默认设为empty的全局方案

解决Spring Boot中Jackson自动初始化未传值的Optional属性为Optional.empty

方案一:通过BeanDeserializerModifier在反序列化前初始化属性

这个方案利用Jackson的beforeDeserialization扩展点,在实例创建完成、Jackson开始赋值之前,自动将所有Optional类型的空属性设为Optional.empty()。

1. 自定义BeanDeserializerModifier及包装类

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;

import java.lang.reflect.Field;
import java.util.Optional;

public class OptionalDefaultDeserializerModifier extends BeanDeserializerModifier {

    @Override
    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        if (deserializer instanceof BeanDeserializer) {
            return new OptionalDefaultBeanDeserializer((BeanDeserializer) deserializer);
        }
        return super.modifyDeserializer(config, beanDesc, deserializer);
    }

    private static class OptionalDefaultBeanDeserializer extends BeanDeserializer implements ResolvableDeserializer {
        private final BeanDeserializer originalDeserializer;

        public OptionalDefaultBeanDeserializer(BeanDeserializer originalDeserializer) {
            super(originalDeserializer);
            this.originalDeserializer = originalDeserializer;
        }

        @Override
        public Object beforeDeserialization(com.fasterxml.jackson.core.JsonParser p, DeserializationContext ctxt) throws java.io.IOException {
            Object bean = super.beforeDeserialization(p, ctxt);
            // 遍历所有字段,初始化空的Optional属性
            for (Field field : bean.getClass().getDeclaredFields()) {
                if (field.getType().equals(Optional.class)) {
                    field.setAccessible(true);
                    try {
                        if (field.get(bean) == null) {
                            field.set(bean, Optional.empty());
                        }
                    } catch (IllegalAccessException e) {
                        // 按需处理异常,比如打印日志
                    }
                }
            }
            return bean;
        }

        @Override
        public void resolve(DeserializationContext ctxt) throws java.io.IOException {
            ((ResolvableDeserializer) originalDeserializer).resolve(ctxt);
        }
    }
}

2. 注册自定义Module

import com.fasterxml.jackson.databind.module.SimpleModule;

public class OptionalDefaultModule extends SimpleModule {
    public OptionalDefaultModule() {
        super();
        setDeserializerModifier(new OptionalDefaultDeserializerModifier());
    }
}

3. 配置Spring Boot Jackson

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new OptionalDefaultModule());
        // 可添加其他Jackson配置,比如JavaTimeModule等
        return objectMapper;
    }
}

方案二:自定义ValueInstantiator在实例化时初始化属性

这个方案直接替换Jackson的默认实例化器,在通过空构造创建对象后,立即初始化所有Optional类型的空属性,完全符合你“空构造实例化后、赋值前”的需求。

1. 自定义ValueInstantiator

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.util.StdValueInstantiator;

import java.lang.reflect.Field;
import java.util.Optional;

public class OptionalDefaultValueInstantiator extends StdValueInstantiator {
    public OptionalDefaultValueInstantiator(StdValueInstantiator src) {
        super(src);
    }

    @Override
    public Object createUsingDefault(DeserializationContext ctxt) throws java.io.IOException {
        Object bean = super.createUsingDefault(ctxt);
        // 初始化空的Optional属性
        for (Field field : bean.getClass().getDeclaredFields()) {
            if (field.getType().equals(Optional.class)) {
                field.setAccessible(true);
                try {
                    if (field.get(bean) == null) {
                        field.set(bean, Optional.empty());
                    }
                } catch (IllegalAccessException e) {
                    // 按需处理异常
                }
            }
        }
        return bean;
    }
}

2. 自定义Modifier替换实例化器

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;

public class OptionalInstantiatorModifier extends BeanDeserializerModifier {
    @Override
    public ValueInstantiator modifyValueInstantiator(DeserializationConfig config, BeanDescription beanDesc, ValueInstantiator defaultInstantiator) {
        if (defaultInstantiator instanceof StdValueInstantiator) {
            return new OptionalDefaultValueInstantiator((StdValueInstantiator) defaultInstantiator);
        }
        return super.modifyValueInstantiator(config, beanDesc, defaultInstantiator);
    }
}

3. 注册Module及配置Spring(同方案一)

只需把Module里的Modifier换成OptionalInstantiatorModifier即可,其余配置和方案一一致。

注意事项

  • 两个方案都会保留类中已手动设置的Optional默认值(比如private Optional<String> name = Optional.empty();),因为代码中判断了属性为null时才赋值。
  • 若需要处理嵌套对象中的Optional属性,可以在遍历字段时增加递归逻辑:判断字段类型是否为自定义非基础类型,然后递归初始化该字段对象的Optional属性。

内容的提问来源于stack exchange,提问作者Iv4n

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:24:58