
本文介绍如何通过自定义序列化器和反序列化转换器,使 jackson 将 null set 序列化为 [],并将空数组 [] 反序列化为 null,同时保持非空集合的默认行为。
在 Jackson 中统一处理集合类(如 Set、List)的空值语义是一个常见但易被误解的需求:业务上常需将 null 集合序列化为 JSON 空数组 [](提升 API 兼容性与前端友好性),而将接收到的空数组 [] 显式还原为 null(以区分“未提供”与“明确提供空集合”)。直接继承 StdDeserializer
正确解法是分层协作:
- 序列化层:使用 JsonSerializer
- 反序列化层:不重写 Deserializer,而是通过 StdConverter 在反序列化完成后对结果做后处理(将空集合转为 null);
- 注册机制:利用 JacksonAnnotationIntrospector 全局生效,或通过 @JsonSerialize / @JsonDeserialize 注解按字段定制。
以下为完整可运行示例(基于 Jackson 2.15+ 和 Spring Boot 常用工具类):
// 全局空集合处理器:自动为所有 Collection 类型启用 null ↔ []
public class EmptyAsNullCollectionJacksonAnnotationIntrospector extends JacksonAnnotationIntrospector {
@Override
public Object findNullSerializer(Annotated a) {
if (Collection.class.isAssignableFrom(a.getRawType())) {
return NullAsEmptyCollectionJsonSerializer.INSTANCE;
}
return super.findNullSerializer(a);
}
@Override
public Object findDeserializationConverter(Annotated a) {
if (List.class.isAssignableFrom(a.getRawType())) {
return EmptyListAsNullConverter.INSTANCE;
}
if (Set.class.isAssignableFrom(a.getRawType())) {
return EmptySetAsNullConverter.INSTANCE;
}
return super.findDeserializationConverter(a);
}
}
// 序列化器:所有 null 集合 → []
class NullAsEmptyCollectionJsonSerializer extends JsonSerializer使用方式一:全局配置(推荐)
var mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.annotationIntrospector(new EmptyAsNullCollectionJacksonAnnotationIntrospector())
.build();使用方式二:字段级注解(更灵活)
public class CollectionsPojo {
@JsonSerialize(nullsUsing = NullAsEmptyCollectionJsonSerializer.class)
@JsonDeserialize(converter = EmptySetAsNullConverter.class)
private Set tags;
@JsonSerialize(nullsUsing = NullAsEmptyCollectionJsonSerializer.class)
@JsonDeserialize(converter = EmptyListAsNullConverter.class)
private List ids;
} ✅ 效果验证:
- nullSet → "nullSet": [](序列化)→ 反序列化后为 null;
- emptySet = Set.of() → "emptySet": [] → 反序列化后为 null;
- setOfOne = Set.of("A") → "setOfOne": ["A"] → 反序列化后仍为 ["A"]。
⚠️ 注意事项:
- StdConverter 是反序列化后置处理,不影响原始解析逻辑,因此安全可靠;
- findNullSerializer 仅作用于 null 值,不干扰非空集合的默认序列化;
- 若项目中已存在自定义 AnnotationIntrospector,需合并逻辑而非直接替换;
- CollectionUtils.isEmpty() 同时兼容 null 和空集合,是安全判断首选。
此方案兼顾简洁性、可维护性与扩展性,无需侵入业务代码,即可统一治理集合空值语义。










