使用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
相关产品推荐
相关产品推荐

