Java如何动态移除请求体中空或null的节点、数组
问题根因
@JsonInclude(value = JsonInclude.Include.NON_NULL)的生效规则是仅跳过值为null的字段,你当前场景里的空节点都不属于null值范畴:
country字段不是null,是一个所有属性均为null的空POJO实例,默认会序列化为{}phoneNumbers、addresses字段本身不是null,是已经初始化的List集合,集合内存储的也是空POJO实例,默认会序列化为包含空对象的数组
以上场景都不在NON_NULL的处理范围内,所以注解无法实现空节点移除效果。
通用无硬编码解决方案
通过Jackson全局配置+通用序列化规则实现自动过滤,不需要针对phoneNumbers、country这类固定字段写死排除逻辑,适配所有动态请求体场景:
1. 配置全局序列化包含规则
替换仅判断null的规则,在ObjectMapper层面统一配置非空判定标准,覆盖空字符串、空集合、空数组、空POJO场景:
ObjectMapper objectMapper = new ObjectMapper(); // 全局跳过null、空字符串、空集合、空数组、空Map值 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); // 补充配置:所有无有效属性的空POJO对象也跳过序列化 objectMapper.configOverride(Object.class) .setInclude(JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, JsonInclude.Include.NON_EMPTY));
2. 处理集合/数组内嵌套空对象的场景
上述配置可以过滤本身为空的集合,但无法处理「集合长度不为0、但内部全是空POJO」的场景(比如你当前返回的"phoneNumbers": [{}]结构),需要注册通用序列化修改器,自动剔除集合内的空元素,过滤后集合为空则直接不输出对应节点:
objectMapper.registerModule(new SimpleModule() { @Override public void setupModule(SetupContext context) { context.addBeanSerializerModifier(new BeanSerializerModifier() { @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { beanProperties.forEach(propertyWriter -> { Class<?> rawClass = propertyWriter.getType().getRawClass(); // 仅处理集合、数组类型属性,不影响其他字段逻辑 if (Collection.class.isAssignableFrom(rawClass) || propertyWriter.getType().isArrayType()) { propertyWriter.assignSerializer(new JsonSerializer<Object>() { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { Collection<?> sourceCollection = value instanceof Collection ? (Collection<?>) value : Arrays.asList((Object[]) value); // 过滤集合内所有无有效属性的空对象 List<Object> validElements = sourceCollection.stream() .filter(element -> !checkIsEmptyObject(element)) .collect(Collectors.toList()); // 过滤后无有效元素的集合直接写null,交由全局NON_EMPTY规则跳过该节点 if (validElements.isEmpty()) { gen.writeNull(); return; } // 输出有效元素组成的数组 gen.writeStartArray(); for (Object element : validElements) { gen.writeObject(element); } gen.writeEndArray(); } }); } }); return beanProperties; } }); } // 通用空对象判定:对象序列化后无任何属性即为空对象 private boolean checkIsEmptyObject(Object obj) { if (obj == null) return true; JsonNode jsonNode = objectMapper.valueToTree(obj); return jsonNode.isObject() && jsonNode.size() == 0; } });
效果说明
配置完成后,所有序列化逻辑自动执行:
- 自动跳过null值、空字符串、空集合、空数组、空POJO对象
- 自动剔除集合/数组内的空对象元素,剔除后集合为空则不输出对应节点
- 完全不需要硬编码指定待排除的字段名,适配任意动态增减字段的POST请求场景
- 序列化输出结果和你期望的结构完全一致,仅保留携带有效值的节点。
内容的提问来源于stack exchange,提问作者Arpita Garg
相关产品推荐
相关产品推荐

