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

Java中MongoDB带@KebabCaseStore注解的通用枚举转换器实现咨询

实现带@KebabCaseStore注解的通用MongoDB枚举转换器

问题背景

MongoDB中以kebab-case格式存储了大量枚举值,但Java代码里所有枚举都用SCREAMING_SNAKE_CASE格式。基于Spring Data MongoDB开发新微服务时,需要保证读写枚举时自动在两种格式间转换,且不用为每个枚举单独写自定义转换器。

解决方案

可以通过自定义注解+Spring Data MongoDB的GenericConverter实现通用枚举转换逻辑,仅对标记了注解的枚举生效,兼顾兼容性与通用性。

1. 定义@KebabCaseStore注解

创建用于标记需要进行格式转换的枚举类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface KebabCaseStore {
}

2. 实现通用读转换器(MongoDB → Java)

将MongoDB中的kebab-case字符串转换为Java枚举的SCREAMING_SNAKE_CASE格式:

@Component
public class KebabCaseToEnumConverter implements GenericConverter {

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, Enum.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }

        Class<?> enumType = targetType.getType();
        // 仅处理标记了@KebabCaseStore的枚举
        if (!enumType.isAnnotationPresent(KebabCaseStore.class)) {
            return Enum.valueOf((Class<? extends Enum<?>>) enumType, (String) source);
        }

        // kebab-case转SCREAMING_SNAKE_CASE:替换连字符为下划线并转大写
        String enumName = ((String) source).replace("-", "_").toUpperCase();
        return Enum.valueOf((Class<? extends Enum<?>>) enumType, enumName);
    }
}

3. 实现通用写转换器(Java → MongoDB)

将Java枚举的SCREAMING_SNAKE_CASE格式转换为MongoDB存储的kebab-case字符串:

@Component
public class EnumToKebabCaseConverter implements GenericConverter {

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(Enum.class, String.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }

        Enum<?> enumValue = (Enum<?>) source;
        Class<?> enumType = sourceType.getType();
        // 仅处理标记了@KebabCaseStore的枚举
        if (!enumType.isAnnotationPresent(KebabCaseStore.class)) {
            return enumValue.name();
        }

        // SCREAMING_SNAKE_CASE转kebab-case:转小写并替换下划线为连字符
        return enumValue.name().toLowerCase().replace("_", "-");
    }
}

4. 注册转换器到Spring上下文

通过配置类将自定义转换器注册到MongoDB的转换体系中:

@Configuration
public class MongoConfig {

    private final KebabCaseToEnumConverter kebabCaseToEnumConverter;
    private final EnumToKebabCaseConverter enumToKebabCaseConverter;

    // 构造注入转换器
    public MongoConfig(KebabCaseToEnumConverter kebabCaseToEnumConverter,
                       EnumToKebabCaseConverter enumToKebabCaseConverter) {
        this.kebabCaseToEnumConverter = kebabCaseToEnumConverter;
        this.enumToKebabCaseConverter = enumToKebabCaseConverter;
    }

    @Bean
    public MongoCustomConversions customConversions() {
        return new MongoCustomConversions(Arrays.asList(
                kebabCaseToEnumConverter,
                enumToKebabCaseConverter
        ));
    }
}

5. 使用示例

给需要进行格式转换的枚举类添加@KebabCaseStore注解即可:

@KebabCaseStore
public enum OrderStatus {
    CREATED,
    PROCESSING,
    SHIPPED,
    DELIVERED
}

此时:

  • 从MongoDB读取"created"会自动转为OrderStatus.CREATED
  • 写入MongoDB时,OrderStatus.PROCESSING会自动转为"processing"

注意事项

  • 确保枚举的格式映射是严格的:SCREAMING_SNAKE_CASE与kebab-case仅通过大小写和下划线/连字符替换对应,无特殊命名规则差异
  • 若部分枚举需要特殊转换逻辑,可单独编写对应转换器,Spring会优先使用更具体的类型转换器
  • 未标记@KebabCaseStore的枚举仍会使用Spring Data MongoDB的默认枚举转换逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:27:21