
本文详解如何在 Jackson 序列化中真正跳过空集合(如 Collections.emptyList())或自定义 POJO(如 Mgmt)字段,避免输出 "list": [] 或 "mgmt": {},通过 @JsonInclude(NON_EMPTY) 与 CUSTOM 模式结合 valueFilter 实现语义级精准过滤。
本文详解如何在 jackson 序列化中真正跳过空集合(如 `collections.emptylist()`)或自定义 pojo(如 `mgmt`)字段,避免输出 `"list": []` 或 `"mgmt": {}`,通过 `@jsoninclude(non_empty)` 与 `custom` 模式结合 valuefilter 实现语义级精准过滤。
在使用 Jackson 进行 JSON 序列化时,开发者常依赖 @JsonInclude(JsonInclude.Include.NON_EMPTY) 注解来自动排除空值字段。该策略对标准类型(如 String、List、Map、数组等)天然有效——当 List 为 null 或 isEmpty() 时,字段将被完全省略。例如:
public class MyClass {
private String type;
private String name;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<object> list; // ✅ 空列表时自动跳过,不输出 "list": []
}</object>
运行以下代码:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); // 全局配置(可选)
MyClass obj = new MyClass("My Name", "My Type", Collections.emptyList());
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj));
输出结果即为期望的精简 JSON:
{
"type" : "My Name",
"name" : "My Type"
}
✅ 无需自定义 JsonSerializer,也无需额外配置——只要字段类型是 Jackson 原生支持的“容器类型”,NON_EMPTY 即可开箱即用。
⚠️ 但注意:此行为仅适用于标准集合/字符串等,不适用于自定义 POJO。例如,若 list 字段被替换为 Mgmt mgmt(一个含 List 的类),则 @JsonInclude(NON_EMPTY) 将失效——因为 Jackson 默认无法递归判断 Mgmt 是否“业务上为空”。此时 new Mgmt() 仍会序列化为 "mgmt": {}。
要解决 POJO 级别的语义空值判定,必须启用 CUSTOM 模式并提供 valueFilter:
✅ 正确方案:@JsonInclude(CUSTOM) + 自定义 valueFilter
// 定义空值判定逻辑:仅当 mgmt.values 为空时视为“应排除”
public static class MgmtEmptyFilter {
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Mgmt)) return false; // 类型安全:非 Mgmt 不参与过滤
Mgmt mgmt = (Mgmt) obj;
return mgmt.values == null || mgmt.values.isEmpty(); // true → 排除该字段
}
}
// 应用于目标字段
public class Test {
@JsonInclude(
value = JsonInclude.Include.CUSTOM,
valueFilter = MgmtEmptyFilter.class
)
Mgmt mgmt;
}
? 关键点:
valueFilter.equals(obj)返回true表示“该值应被排除”(Jackson 的约定,非直觉语义)。
❌ 常见误区与避坑指南
误用
@JsonSerialize干预字段存在性:自定义JsonSerializer(如题中CustomSearilizer)仅控制如何写入值,不控制字段是否写出。即使你在serialize()中什么也不写,writeFieldName("list")已由 Jackson 内部触发,最终仍会生成"list": []。因此,字段级存在性控制必须交由@JsonInclude而非@JsonSerialize。全局配置与字段级注解冲突:若
ObjectMapper设置了setSerializationInclusion(NON_EMPTY),又在字段上显式标注@JsonInclude(ALWAYS),后者优先级更高。建议统一策略,避免隐式覆盖。NON_EMPTY的完整判定范围:除null和空集合外,还涵盖空字符串、空数组、Optional.empty()、AtomicReference(null)等——但不包含任何自定义类,除非显式声明CUSTOM过滤器。
总结
| 场景 | 推荐方式 | 效果 |
|---|---|---|
标准集合(List/Set/Map)、字符串、数组 |
@JsonInclude(NON_EMPTY)(类级或字段级) |
✅ 自动跳过空值,输出无该字段 |
自定义 POJO(如 Mgmt),需按内部状态判定 |
@JsonInclude(CUSTOM, valueFilter = XxxFilter.class) |
✅ 精准语义控制,完全排除 |
| 强制校验必填字段非空(否则中断序列化) | 自定义 JsonSerializer + 手动判空抛异常 |
⚠️ 适用于数据完整性强约束场景 |
掌握 NON_EMPTY 的适用边界与 CUSTOM 模式的扩展能力,即可在 API 响应中优雅剔除冗余空结构,交付简洁、语义清晰的 JSON。










