Jackson转换含枚举属性对象为Map时枚举值变为String类型问题
问题原因
- 你添加的
@Enumerated(EnumType.STRING)是JPA持久层规范的注解,仅对Hibernate这类ORM框架的数据库存储逻辑生效,Jackson完全不识别这个注解,不会对ObjectMapper的类型转换行为产生任何影响。 - 核心问题来自Jackson的默认转换逻辑:
convertValue的执行流程等价于先将源对象序列化为JSON中间结构,再把中间结果反序列化为你传入的目标类型。你传入的目标类型是无泛型声明的原始Map.class,Jackson会将Map的value类型识别为通用Object,而JSON本身没有枚举类型,Jackson默认会把枚举值序列化为枚举名称字符串存入中间结构,最终反序列化得到的Map里,color字段自然是String类型——就算你删掉@Enumerated注解,默认转换结果依然是String。
解决方案
根据实际业务场景选择对应方案即可:
方案1:全局配置保留枚举实例
如果所有枚举类型在转Map时都需要保留原始枚举对象,给ObjectMapper注册自定义枚举序列化器即可:
// 自定义枚举序列化器,直接保留原始枚举引用 class EnumPreserveSerializer extends StdSerializer<Enum> { protected EnumPreserveSerializer() { super(Enum.class); } @Override public void serialize(Enum value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeEmbeddedObject(value); } } // 初始化MAPPER时注册模块 ObjectMapper MAPPER = new ObjectMapper(); SimpleModule enumModule = new SimpleModule(); enumModule.addSerializer(Enum.class, new EnumPreserveSerializer()); MAPPER.registerModule(enumModule);
配置完成后再调用convertValue,Map里的color字段就会保留原始的Color枚举类型。注意这个配置不要和普通JSON序列化共用ObjectMapper实例,JSON本身不支持枚举类型,会导致序列化报错,建议给转Map场景单独维护专用的Mapper实例。
方案2:单字段指定保留枚举
如果只有个别枚举字段需要保留原类型,不需要修改全局Mapper配置,给对应字段添加Jackson的序列化注解即可:
public class Car{ ... @Enumerated(EnumType.STRING) // 该注解仅给JPA持久层使用,和Jackson逻辑无关 @JsonSerialize(using = EnumPreserveSerializer.class) private Color color; ... }
注解里引用的序列化器直接复用方案1中定义的EnumPreserveSerializer即可。
方案3:手动转换枚举值
如果只是需要读取枚举值,不需要Map内存储枚举实例,不需要修改Mapper配置,取值时手动转换即可:
Map<String, Object> toMap = MAPPER.convertValue(t, Map.class); Color carColor = Color.valueOf((String) toMap.get("color"));
这个方案改造成本最低,适合转换后仅需要读取枚举值的场景。
内容的提问来源于stack exchange,提问作者travis scott
相关产品推荐
相关产品推荐

