
本文详解 Jackson 中 @JsonInclude 对自定义类(如 Mgmt)失效的原因,并提供基于 CUSTOM 模式的可靠解决方案,通过自定义 valueFilter 实现“仅当内部集合非空时才序列化该对象字段”的语义控制。
本文详解 jackson 中 `@jsoninclude` 对自定义类(如 `mgmt`)失效的原因,并提供基于 `custom` 模式的可靠解决方案,通过自定义 `valuefilter` 实现“仅当内部集合非空时才序列化该对象字段”的语义控制。
在使用 Jackson 进行 JSON 序列化时,开发者常依赖 @JsonInclude(JsonInclude.Include.NON_EMPTY) 来自动跳过空值字段。然而,该策略对标准类型(如 String、Collection、Map 等)有效,对自定义 POJO 类(如 Mgmt)却默认不生效——因为 Jackson 无法自动推断“一个 Mgmt 实例是否为空”。即使 Mgmt.values 是空列表,Mgmt 对象本身仍被视为“非空”,导致序列化结果中出现冗余的 "mgmt": {}。
要真正实现“仅当 Mgmt.values 非空时才输出 mgmt 字段”,必须显式定义业务层面的“空”语义,并交由 Jackson 通过自定义过滤器执行判断。
✅ 正确做法:使用 @JsonInclude(value = CUSTOM, valueFilter = ...)
核心思路是:编写一个 valueFilter 类,其 equals() 方法返回 true 表示“该值应被排除”(注意:这是 Jackson 的约定,而非直觉上的“相等”含义)。
以下为完整可运行示例:
// 自定义空值判定逻辑:当 Mgmt.values 为空时,视为“应排除”
public static class MgmtFilter {
@Override
public boolean equals(Object obj) {
// 若非 Mgmt 类型,不参与过滤(避免误判),返回 false
if (!(obj instanceof Mgmt)) {
return false;
}
Mgmt mgmt = (Mgmt) obj;
// values 为空 → 当前 Mgmt 实例应被排除 → 返回 true
return mgmt.values == null || mgmt.values.isEmpty();
}
}
// 在目标字段上应用自定义过滤
class Test {
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = MgmtFilter.class)
Mgmt mgmt;
}
class Mgmt {
List<String> values;
// 建议添加 getter/setter 或启用 @JsonAutoDetect
}✅ 序列化效果对比:
- new Test().mgmt = new Mgmt(); → 输出 {}(无 mgmt 字段)
- new Test().mgmt = new Mgmt().values(Arrays.asList("a")); → 输出 {"mgmt":{"values":["a"]}}
⚠️ 关键注意事项
- valueFilter 类必须重写 equals(Object),且逻辑需严格遵循“返回 true 表示排除”;
- 不需要重写 hashCode()(Jackson 仅调用 equals);
- valueFilter 实例由 Jackson 内部缓存并复用,必须是无状态的(stateless),不可持有外部引用或可变成员;
- 若 Mgmt 类含多个判空字段(如 values 和 config),应在 equals() 中综合判断;
- 推荐将 MgmtFilter 设为 static 内部类或独立工具类,提升可测试性与复用性。
? 总结
@JsonInclude.NON_EMPTY 并非万能——它只理解 JDK 原生类型的“空”,而领域对象的“空”需由开发者明确定义。通过 CUSTOM + valueFilter 模式,你既能保持序列化逻辑的声明式简洁,又能精准表达业务语义。这是 Jackson 高级定制能力的典型实践,适用于 API 响应精简、配置对象条件导出等真实场景。










