Jackson序列化:忽略空值及子对象全空的父类字段解决方案
解决方案:Jackson序列化时忽略空对象及空值,同时保留非空父对象
看起来你需要精准控制Jackson的JSON序列化行为:既要忽略空的子对象,又要在父对象有非空属性时保留父对象,还要在父类所有属性都为空时完全去掉父类字段。我来给你几个可行的方案:
方案一:局部字段自定义空对象过滤器(简单直接)
如果只是少数字段需要处理,推荐用Jackson的@JsonInclude(CUSTOM)结合自定义过滤器,判断对象是否所有属性为空,为空则忽略整个字段。
步骤1:创建空对象判断过滤器
public class EmptyObjectFilter { @Override public boolean equals(Object obj) { if (obj == null) return true; // 反射检查对象所有属性是否为null或空字符串 try { for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); Object value = field.get(obj); if (value != null) { // 字符串需额外判断非空 if (value instanceof String && !((String) value).isEmpty()) { return false; } // 非字符串类型只要非null就视为有效 if (!(value instanceof String)) { return false; } } } // 所有属性都为空/空字符串,返回true表示忽略该字段 return true; } catch (IllegalAccessException e) { throw new RuntimeException("Failed to check empty object", e); } } }
步骤2:在目标字段上应用过滤器
修改你的类A,给需要判断的子对象字段加上自定义过滤器,同时保留全局的空值排除配置:
@JsonInclude(JsonInclude.Include.NON_EMPTY) // 全局排除空值、空集合、空字符串等 public class A { // 当B对象所有属性为空时,忽略这个字段 @JsonProperty("classA.empName") @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = EmptyObjectFilter.class) public B empName = new B(); @JsonProperty("classA.emp_name") public int age = 25; // 其他属性... } // 给B类也加上空值排除,确保B的空属性不被序列化 @JsonInclude(JsonInclude.Include.NON_EMPTY) public class B { // B的属性,比如: public String name; public String department; }
这样配置后:
- 如果
empName的B对象所有属性都是null/空字符串,classA.empName字段会被完全忽略; - 如果B有非空属性,该字段会正常序列化;
- 类A的
age属性(非空)会保留,确保父对象A被正常输出。
方案二:全局配置空对象忽略(适合大量类场景)
如果你有很多类需要处理空对象,可以通过自定义BeanSerializerModifier全局配置,避免每个字段都加注解。
步骤1:创建序列化器修改器
public class EmptyObjectSerializerModifier extends BeanSerializerModifier { @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { for (BeanPropertyWriter writer : beanProperties) { Class<?> propType = writer.getType().getRawClass(); // 只处理自定义对象(排除基本类型、字符串、集合等) if (!propType.isPrimitive() && !String.class.isAssignableFrom(propType) && !Collection.class.isAssignableFrom(propType)) { writer.assignNullSerializer(new JsonSerializer<Object>() { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { boolean isEmpty = checkIfObjectIsEmpty(value); if (!isEmpty) { // 对象非空,正常序列化 gen.writeObject(value); } // 对象为空,不写入任何内容,即忽略该字段 } }); } } return beanProperties; } private boolean checkIfObjectIsEmpty(Object obj) { if (obj == null) return true; try { for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); Object value = field.get(obj); if (value != null) { if (value instanceof String && !((String) value).isEmpty()) { return false; } if (!(value instanceof String)) { return false; } } } return true; } catch (IllegalAccessException e) { throw new IOException("Failed to check empty object", e); } } }
步骤2:注册到ObjectMapper
在创建ObjectMapper时添加这个修改器,并设置全局空值排除:
ObjectMapper mapper = new ObjectMapper(); // 注册自定义修改器 mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new EmptyObjectSerializerModifier())); // 全局排除空值、空集合、空字符串 mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
这样所有自定义对象类型的字段,只要对象所有属性为空,就会被自动忽略,无需在每个字段上加注解。
额外处理:排除基本类型默认值
如果你的需求还包括排除基本类型的默认值(比如int的0、boolean的false),可以把全局的NON_EMPTY换成NON_DEFAULT,或者在特定字段上单独加@JsonInclude(JsonInclude.Include.NON_DEFAULT)。
比如修改类A的age字段:
@JsonProperty("classA.emp_name") @JsonInclude(JsonInclude.Include.NON_DEFAULT) public int age = 25;
这样当age被设为0(int的默认值)时,该字段会被忽略;如果是25则正常保留。
内容的提问来源于stack exchange,提问作者Vipin Dube
相关产品推荐
相关产品推荐

