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

Spring枚举MongoDB序列化异常:自定义值读写失败

解决Spring Data MongoDB枚举小写存储/读取问题

这个问题我之前也踩过坑!核心原因是Spring Data MongoDB 并没有使用Jackson来处理枚举的序列化/反序列化——它自带了一套默认的枚举转换逻辑:存的时候直接写枚举的大写名称,读的时候调用Enum.valueOf()解析,所以你加的@JsonCreator、@JsonValue注解只在HTTP请求的@RequestBody处理中生效,对MongoDB的读写完全没影响。

下面给你两种靠谱的解决办法,推荐第一种:

方法一:自定义MongoDB枚举转换器(最通用)

我们需要写两个转换器,分别负责把枚举序列化为MongoDB的字符串,以及把MongoDB的字符串反序列化为枚举,然后注册到Spring Data MongoDB的配置中。

1. 写序列化转换器(枚举转字符串)

这个转换器会在保存数据时,把State枚举转成你定义的小写value:

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;

// @WritingConverter标记这是写入MongoDB时用的转换器
@WritingConverter
public class StateToStringConverter implements Converter<State, String> {
    @Override
    public String convert(State source) {
        // 调用你枚举里的toValue()方法,返回小写的自定义值
        return source.toValue();
    }
}

2. 写反序列化转换器(字符串转枚举)

这个转换器会在读取数据时,把MongoDB里的小写字符串转成对应的State枚举:

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;

// @ReadingConverter标记这是从MongoDB读取时用的转换器
@ReadingConverter
public class StringToStateConverter implements Converter<String, State> {
    @Override
    public State convert(String source) {
        // 调用你枚举里的fromValue()方法,根据自定义值匹配枚举
        return State.fromValue(source);
    }
}

3. 注册转换器到MongoDB配置

创建一个配置类,把上面两个转换器注册进去:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;

import java.util.Arrays;

@Configuration
public class MongoConfig {

    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Arrays.asList(
                new StateToStringConverter(),
                new StringToStateConverter()
        ));
    }
}

这样配置完成后,MongoDB读写State枚举时就会用你自定义的逻辑:

  • 保存数据:State.GREEN会被存成"vert"
  • 读取数据:从MongoDB拿到"vert"会被转成State.GREEN,不会再抛出IllegalArgumentException

方法二:用MongoDB的@Field配合SpEL(简化版,仅适用于单个枚举)

如果不想写转换器,也可以直接在实体类的枚举字段上用SpEL表达式指定存储值:

@Document(collection = "my_collec") 
public class MyClass { 
    @Id 
    private ObjectId _id; 
    // 保存时用枚举的toValue(),读取时用State.fromValue()
    @Field(value = "st", targetType = String.class)
    private State state; 

    // 注意:需要给state字段加对应的getter/setter,或者用Lombok
    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    // 读取时的转换逻辑:MongoDB的字符串转枚举
    @Value("#{T(com.yourpackage.enums.State).fromValue(target.state)}")
    public void setState(String stateStr) {
        this.state = State.fromValue(stateStr);
    }
}

不过这种方式不如转换器通用,如果你有多个枚举需要处理,还是推荐第一种方法。

为什么之前的Jackson注解没用?

再补个知识点:Spring Data MongoDB默认用MappingMongoConverter处理对象和MongoDB文档的转换,其中枚举的默认转换器是EnumWritingConverter和EnumReadingConverter——这两个转换器直接调用枚举的name()和Enum.valueOf(),完全忽略Jackson的注解,所以你的Jackson配置对MongoDB读写无效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:21:47