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

使用Jackson库实现Java中Map<Enum<?>, Object>的序列化与反序列化

解决Jackson序列化/反序列化Map<Enum<?>, Object>的问题

默认Jackson序列化枚举类型的Map键时,只会输出枚举常量的名称(如I1),导致反序列化时无法确定该名称归属哪个枚举类。要实现全限定类名+常量名作为JSON键的序列化/反序列化,需要自定义Jackson的键序列化器和反序列化器。

1. 自定义枚举键序列化器

将枚举实例序列化为全类名.常量名格式的字符串:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.lang.Enum;

public class EnumFullNameKeySerializer extends StdSerializer<Enum<?>> {
    public EnumFullNameKeySerializer() {
        super(Enum.class, true);
    }

    @Override
    public void serialize(Enum<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        String key = value.getClass().getName() + "." + value.name();
        gen.writeFieldName(key);
    }
}

2. 自定义枚举键反序列化器

解析全类名.常量名格式的字符串,还原为对应的枚举实例:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class EnumFullNameKeyDeserializer extends KeyDeserializer {
    @Override
    public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
        String[] parts = key.split("\\.", 2);
        if (parts.length != 2) {
            throw new JsonProcessingException("无效的枚举键格式: " + key) {};
        }

        String className = parts[0];
        String enumName = parts[1];

        try {
            Class<?> enumClass = Class.forName(className);
            Method valueOfMethod = enumClass.getMethod("valueOf", String.class);
            return valueOfMethod.invoke(null, enumName);
        } catch (ReflectiveOperationException e) {
            throw new JsonProcessingException("反序列化枚举键失败: " + key, e) {};
        }
    }
}

3. 配置ObjectMapper并测试

通过SimpleModule注册自定义序列化/反序列化器,然后进行序列化和反序列化测试:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.TypeReference;

import java.util.Map;

public class Main {
    public enum IntParam {I1, I2, I3}
    public enum DoubleParam {D1, D2, D3}
    public enum StringParam {S1, S2, S3}

    public static void main(String[] args) throws Exception {
        // 注册自定义模块
        SimpleModule enumKeyModule = new SimpleModule();
        enumKeyModule.addKeySerializer(Enum.class, new EnumFullNameKeySerializer());
        enumKeyModule.addKeyDeserializer(Enum.class, new EnumFullNameKeyDeserializer());

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(enumKeyModule);

        // 序列化
        Map<Enum<?>, Object> config = Map.of(
                IntParam.I1, 1,
                DoubleParam.D2, 1.0,
                StringParam.S3, "sss"
        );
        String json = mapper.writeValueAsString(config);
        System.out.println(json);
        // 输出:{"Main.IntParam.I1":1,"Main.DoubleParam.D2":1.0,"Main.StringParam.S3":"sss"}

        // 反序列化
        Map<Enum<?>, Object> deserializedConfig = mapper.readValue(json, new TypeReference<Map<Enum<?>, Object>>() {});
        System.out.println(deserializedConfig);
        // 输出:{I1=1, D2=1.0, S3=sss}
    }
}

注意事项

  • 第三方枚举类必须在当前类路径下可访问,且默认的valueOf方法可用(所有Java枚举都自带该方法)
  • 若枚举有特殊的实例获取逻辑,可在反序列化器中调整反射调用逻辑
  • 确保所有枚举常量名全局唯一(符合题目给定的前提)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 13:58:39