如何让Spring匹配大小写不一致的枚举类型?
问题描述
原本定义的Kotlin枚举:
enum class CallbackStatus{ success, failed }
因ktlint提示枚举名称小写不符合规范,修改为:
enum class CallbackStatus{ SUCCESS, FAILED }
修改后多个测试失败,报错信息:
Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.PathVariable no.posten.push.notification.CallbackStatus] for value 'failed'; nested exception is java.lang.IllegalArgumentException: No enum constant mypackage.CallbackStatus.failed
该枚举用于Spring接口的路径变量:
@PostMapping("{status}") fun handleCallback( @PathVariable callbackReference: String, @PathVariable status: CallbackStatus, @RequestBody callback: Callback, @RequestHeader(notificationEngineCallbackHeader) callbackSecret: String, ): ResponseEntity<Any> =
需求:让Spring自动将字符串"failed"转换为CallbackStatus.FAILED,疑问:是否需要重写StringToEnumConverterFactory?
解决方案
不需要重写StringToEnumConverterFactory,以下几种简便方式即可解决:
1. 自定义枚举转换方法 + 注册Converter
在枚举类中添加静态方法处理字符串匹配,再注册自定义Converter到Spring:
enum class CallbackStatus { SUCCESS, FAILED; companion object { fun fromString(value: String): CallbackStatus { return values().firstOrNull { it.name.equals(value, ignoreCase = true) } ?: throw IllegalArgumentException("Invalid status: $value") } } }
创建自定义Converter:
@Component class StringToCallbackStatusConverter : Converter<String, CallbackStatus> { override fun convert(source: String): CallbackStatus { return CallbackStatus.fromString(source) } }
Spring会自动识别并使用该Converter替代默认枚举转换逻辑。
2. 使用@JsonCreator注解(推荐)
在枚举的静态转换方法上添加@JsonCreator,同时配合@JvmStatic让Spring能识别该方法,既支持JSON序列化,也能处理路径变量的转换:
enum class CallbackStatus { SUCCESS, FAILED; companion object { @JsonCreator @JvmStatic fun fromString(value: String): CallbackStatus { return values().firstOrNull { it.name.equals(value, ignoreCase = true) } ?: throw IllegalArgumentException("Invalid status: $value") } } }
这种方式无需额外注册组件,代码侵入性低,实现简洁。
3. 全局配置枚举忽略大小写转换
如果希望所有枚举都支持忽略大小写的字符串转换,可以通过配置ConversionService实现:
@Configuration class WebConfig : WebMvcConfigurer { override fun addFormatters(registry: FormatterRegistry) { registry.addConverter(String::class.java, Enum::class.java) { source, targetType -> @Suppress("UNCHECKED_CAST") val enumType = targetType as Class<Enum<*>> Enum.valueOf(enumType, source.uppercase()) } } }
该配置会对所有枚举生效,自动将输入字符串转为大写后匹配枚举常量。
总结
优先选择第二种@JsonCreator的方式,简洁且适配场景广;若仅需单独处理某个枚举,用第一种自定义Converter;全局所有枚举都需要忽略大小写时,用第三种配置方案。无需重写StringToEnumConverterFactory,上述方式更灵活易维护。
内容的提问来源于stack exchange,提问作者oligofren
相关产品推荐
相关产品推荐

