You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Set集合序列化/反序列化器:空值与空集合互转需求

嘿,我懂你现在的困扰——之前处理字符串空值转null的方法用到了asText(),但集合这块JsonNode没提供对应的asSet(),确实得换个思路。刚好我之前也处理过类似的需求,给你分享一下可行的实现方案:

自定义Jackson序列化/反序列化器处理Set的null与空集合转换

我们需要分别实现序列化器(把null Set转成空Set)和反序列化器(把空Set转成null),借助Jackson的标准扩展类来实现,同时复用它的默认序列化逻辑,不用自己手动解析集合元素。

一、反序列化器:空Set → null

核心逻辑:读取JSON节点后,判断是否为空数组(对应空Set),如果是直接返回null;否则交给Jackson默认逻辑反序列化成带元素的Set。这里用convertValue来把JsonNode转成Set,避免手动处理泛型和元素解析。

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.util.Set;

@JsonComponent
public class EmptySetToNullDeserializer extends StdDeserializer<Set<?>> {

    public EmptySetToNullDeserializer() {
        super(Set.class);
    }

    @Override
    public Set<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.readValueAsTree();
        
        // 节点为null直接返回null
        if (node == null) {
            return null;
        }
        
        // 空数组对应空Set,返回null
        if (node.isArray() && node.size() == 0) {
            return null;
        }
        
        // 复用Jackson默认逻辑反序列化为Set
        return ctxt.getObjectMapper().convertValue(node, new TypeReference<Set<?>>() {});
    }
}

二、序列化器:null Set → 空Set

序列化逻辑更简单:当Set为null时,序列化为空数组;否则正常输出集合内容。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;

@JsonComponent
public class NullSetToEmptySerializer extends JsonSerializer<Set<?>> {

    @Override
    public void serialize(Set<?> set, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // null Set转成空Set序列化
        if (set == null) {
            gen.writeObject(Collections.emptySet());
        } else {
            // 有元素时正常序列化
            gen.writeObject(set);
        }
    }
}

三、使用方式

全局生效

如果是Spring Boot项目,给两个类加上@JsonComponent注解后,Spring会自动把它们注册到Jackson的ObjectMapper中,全局所有Set类型都会应用这个规则。

局部生效

如果只想给特定字段用,在字段上单独指定序列化器/反序列化器:

public class DemoEntity {
    @JsonSerialize(using = NullSetToEmptySerializer.class)
    @JsonDeserialize(using = EmptySetToNullDeserializer.class)
    private Set<String> tags;
    
    // getter、setter省略
}

为什么你之前的思路不适用?

你之前尝试用node.asSet(),但JsonNode确实没有这个方法——JSON里的集合对应数组节点,不是简单的文本节点,所以不能用处理字符串的方式。用convertValue可以让Jackson帮我们完成数组到Set的转换,同时自动处理集合内元素的序列化/反序列化,不用自己遍历节点拼接集合。

如果需要处理特定泛型的Set(比如Set<User>),可以把序列化器/反序列化器的泛型改成Set<User>,这样能更精准,但上面的Set<?>版本是全局通用的。

内容的提问来源于stack exchange,提问作者Occams Stubble

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 10:25:46