You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何配置Jackson ObjectMapper以排除所有嵌套布尔字段均为null的空对象

这个问题我之前也碰到过,根源在于你用的@JsonInclude(NON_NULL)只盯着字段本身是不是null——你的holdTypeIndicator是个已经实例化的对象,哪怕它内部所有字段都是null,Jackson也会把这个空对象序列化出来,所以才会出现{"holdTypeIndicator": {}}这种情况。NON_DEFAULTNON_ABSENT也解决不了,因为对象本身不是默认的null值。

下面给你一个全局生效的解决方案,不用挨个给嵌套字段加注解,通过自定义Jackson的序列化器修饰器就能实现“嵌套对象全字段为null时自动排除”的效果:

步骤1:自定义序列化器修饰器

这个修饰器会拦截所有对象的序列化过程,检查对象的所有字段是否都为null,如果是,就把它当作null处理,这样NON_NULL策略就会自动排除这个字段:

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.lang.reflect.Field;

public class NullObjectSerializerModifier extends BeanSerializerModifier {

    @Override
    public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
        return new NullObjectWrapperSerializer((JsonSerializer<Object>) serializer);
    }

    private static class NullObjectWrapperSerializer extends StdSerializer<Object> {
        private final JsonSerializer<Object> delegate;

        public NullObjectWrapperSerializer(JsonSerializer<Object> delegate) {
            super(Object.class);
            this.delegate = delegate;
        }

        @Override
        public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            boolean allFieldsNull = true;
            // 反射遍历对象所有字段,检查是否全为null
            Field[] fields = value.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    if (field.get(value) != null) {
                        allFieldsNull = false;
                        break;
                    }
                } catch (IllegalAccessException e) {
                    // 遇到访问异常时默认视为非空,保证序列化正常进行
                    allFieldsNull = false;
                    break;
                }
            }

            if (allFieldsNull) {
                // 全字段为null时输出null,让NON_NULL策略排除该字段
                gen.writeNull();
            } else {
                // 正常序列化对象
                delegate.serialize(value, gen, provider);
            }
        }
    }
}

步骤2:配置ObjectMapper

把上面的修饰器注册到ObjectMapper中,同时开启全局的NON_NULL排除策略:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.annotation.JsonInclude;

public class CustomObjectMapperFactory {
    public static ObjectMapper create() {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.setSerializerModifier(new NullObjectSerializerModifier());
        mapper.registerModule(module);
        // 全局排除值为null的字段
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return mapper;
    }
}

步骤3:使用自定义ObjectMapper序列化

现在用这个配置好的ObjectMapper来序列化你的对象:

HoldsType holds = new HoldsType();
holds.setHoldTypeIndicator(new HoldTypeIndicatorType()); // 内部所有字段都是null
ObjectMapper mapper = CustomObjectMapperFactory.create();
String json = mapper.writeValueAsString(holds);
// 输出结果:{} —— holdTypeIndicator被自动排除了

补充说明

  • 这个方案是全局生效的,所有自定义类都会被检查,只要对象全字段为null就会被排除,不用修改现有类的注解。
  • 如果只想针对特定类生效,可以在modifySerializer方法里加个判断,比如if (beanDesc.getBeanClass().equals(HoldTypeIndicatorType.class)),再包装序列化器。
  • 如果你类数量不多,也可以用替代方案:在嵌套字段上用@JsonInclude(value = JsonInclude.Include.NON_EMPTY, content = JsonInclude.Include.NON_NULL),然后让嵌套类实现isEmpty()方法,判断自己的字段是否全为null。但这个方案需要每个嵌套类都写isEmpty(),适合小体量场景。

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

火山引擎 最新活动