Spring接收请求参数时String转自定义枚举失败问题求助
我在通过HTTP请求传递排序参数时遇到了问题:控制器接收的是OpenAPI生成的Sort枚举类型参数,但只能识别ASC或DESC格式的参数,无法处理created:ASC这种预期格式的输入。
生成的枚举代码如下:
/** * * Values: ASC,DESC */ enum class Sort(val value: kotlin.String) { @JsonProperty("created:ASC") ASC("created:ASC"), @JsonProperty("created:DESC") DESC("created:DESC") }
发送created:ASC时会抛出400类型不匹配异常,报错栈信息:
org.springframework.web.server.ServerWebInputException: 400 BAD_REQUEST "Type mismatch." Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.v3.oas.annotations.Parameter @jakarta.validation.Valid @org.springframework.web.bind.annotation.RequestParam com.my.app.api.Sort] for value 'created:ASC' Caused by: java.lang.IllegalArgumentException: No enum constant com.my.app.api.Sort.created:ASC at java.base/java.lang.Enum.valueOf(Enum.java:273)
使用的依赖版本:
- spring-boot = 3.0.3
- kotlin = "1.8.0"
- openapi = "7.0.0-beta"
Spring处理@RequestParam这类URL参数的枚举转换时,默认使用Enum.valueOf()方法,只会匹配枚举的名称(比如ASC、DESC),而不是@JsonProperty注解指定的值。@JsonProperty主要用于Jackson处理JSON请求体的序列化/反序列化,对URL参数的转换逻辑不生效。你之前遇到的类似控制器生效的情况,大概率是因为那个接口接收的是JSON请求体,而非URL参数。
1. 自定义Spring枚举转换器
创建一个Spring Converter组件,手动实现字符串到Sort枚举的转换逻辑,匹配枚举的value字段:
import org.springframework.core.convert.converter.Converter import org.springframework.stereotype.Component @Component class StringToSortConverter : Converter<String, Sort> { override fun convert(source: String): Sort? { return Sort.values().firstOrNull { it.value == source } } }
这个转换器会被Spring自动识别,处理@RequestParam到Sort枚举的转换。
2. 修改OpenAPI生成配置(推荐)
因为枚举是OpenAPI自动生成的,手动修改代码会被下次生成覆盖,所以更推荐调整生成配置,让生成的枚举自带正确的转换逻辑:
在OpenAPI规范中明确枚举值
确保你的OpenAPI YAML/JSON里,排序参数的枚举值是created:ASC和created:DESC:
parameters: - name: sort in: query schema: type: string enum: - created:ASC - created:DESC
调整生成器配置
在Gradle/Maven的OpenAPI Generator插件配置中,添加参数让生成的枚举支持基于值的转换:
以Gradle为例:
openApiGenerate { generatorName = "spring" inputSpec = "$rootDir/src/main/resources/openapi.yaml".toString() outputDir = "$buildDir/generated".toString() apiPackage = "com.my.app.api" modelPackage = "com.my.app.model" configOptions = [ enumPropertyNaming: "UPPERCASE", useJackson: "true", delegatePattern: "true", useSpringConverter: "true" // 启用Spring转换器生成 ] }
生成后的枚举会自动包含@JsonValue注解或者对应的转换器逻辑,无需手动修改。
3. 手动添加@JsonValue注解(临时方案)
如果允许临时修改生成的枚举代码,可以给value字段添加@JsonValue注解,让Spring和Jackson都以这个值作为转换依据:
/** * * Values: ASC,DESC */ enum class Sort(val value: kotlin.String) { @JsonProperty("created:ASC") ASC("created:ASC"), @JsonProperty("created:DESC") DESC("created:DESC"); @JsonValue fun getValue(): String = value }
注意:下次生成代码时这个修改会被覆盖,仅作为临时解决办法。
内容的提问来源于stack exchange,提问作者agingcabbage32

