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

如何让Spring Boot适配OpenAPI生成代码中的枚举值?

Spring Boot + OpenAPI Generator 枚举参数自动转换方案

问题背景

我在Spring Boot应用中采用API优先方案,基于自定义的openapi.yaml文件生成代码。其中有一个API接口,接收必填请求参数type,该参数是自定义枚举SomeEnum的数组类型。

问题现象

通过Swagger编辑器生成的请求调用时返回400错误:

curl -X 'GET' \
  'https://localhost:8080/api/1/demo?type=best_value' \
  -H 'accept: application/json'

日志报错信息:

2023-04-06 15:52:05.223  WARN 16396 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.List';   
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@javax.validation.constraints.NotNull @io.swagger.v3.oas.annotations.Parameter @javax.validation.Valid @org.springframework.web.bind.annotation.RequestParam com.ronkitay.openapidemo.model.SomeEnum] for value 'another-value'; 
nested exception is java.lang.IllegalArgumentException: No enum constant com.ronkitay.openapidemo.model.SomeEnum.another-value]

但使用枚举常量名(而非@JsonValue指定的字符串值)调用时可正常工作:

curl  http://localhost:8080/api/1/demo?type=ANOTHER_VALUE

生成的SomeEnum代码如下:

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2023-04-06T15:51:49.262+03:00[Asia/Jerusalem]")
public enum SomeEnum {
  
  VALUE1("value1"),
  
  ANOTHER_VALUE("another-value"),
  
  BEST_VALUE("best_value"),
  
  THEVALUE("thevalue");

  private String value;

  SomeEnum(String value) {
    this.value = value;
  }

  @JsonValue
  public String getValue() {
    return value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  @JsonCreator
  public static SomeEnum fromValue(String value) {
    for (SomeEnum b : SomeEnum.values()) {
      if (b.value.equals(value)) {
        return b;
      }
    }
    throw new IllegalArgumentException("Unexpected value '" + value + "'");
  }
}

当前解决方案

我通过编写自定义转换器实现了预期的参数转换功能:

@Configuration
public class Config implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new SomeEnumFormatter());
    }

    public static class SomeEnumFormatter implements ConverterFactory<String,SomeEnum> {

        @Override
        public <T extends SomeEnum> Converter<String, T> getConverter(Class<T> targetType) {
            return new StringToSomeEnumConverter<>(targetType);
        }

        public static class StringToSomeEnumConverter<T extends SomeEnum> implements Converter<String, T> {

            private Class<T> targetClass;

            public StringToSomeEnumConverter(Class<T> targetClass) {
                this.targetClass = targetClass;
            }

            @Override
            public T convert(String source) {
                return (T) SomeEnum.fromValue(source);
            }
        }
    }
}

核心问题

是否存在Spring或OpenAPI Generator的内置配置,能够自动实现这种枚举参数的转换逻辑,无需为每个枚举单独编写自定义转换器?


答案

有两种更简洁的方案可以替代自定义转换器:

1. OpenAPI Generator 配置自动生成转换器

在OpenAPI Generator的配置中添加以下参数,让生成器自动为所有枚举创建Spring转换器:

  • Maven插件配置:
<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>最新版本</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <!-- 其他配置 -->
                <configOptions>
                    <useSpringConverter>true</useSpringConverter>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>
  • Gradle插件配置:
openApiGenerate {
    // 其他配置
    configOptions = [
        useSpringConverter: "true"
    ]
}

开启useSpringConverter后,生成器会自动为每个枚举生成对应的Converter和ConverterFactory,无需手动编写。

2. Spring全局枚举转换器

编写一个通用的枚举转换器工厂,适配所有带有@JsonCreator静态方法的枚举类,无需为每个枚举单独处理:

import java.lang.reflect.Method;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GlobalEnumConverterConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new GenericEnumConverterFactory());
    }

    public static class GenericEnumConverterFactory implements ConverterFactory<String, Enum<?>> {

        @Override
        public <T extends Enum<?>> Converter<String, T> getConverter(Class<T> targetType) {
            return new GenericEnumConverter<>(targetType);
        }

        private static class GenericEnumConverter<T extends Enum<?>> implements Converter<String, T> {
            private final Class<T> enumType;

            public GenericEnumConverter(Class<T> enumType) {
                this.enumType = enumType;
            }

            @Override
            public T convert(String source) {
                if (source == null || source.isEmpty()) {
                    return null;
                }
                try {
                    // 优先调用枚举的fromValue静态方法
                    Method fromValueMethod = enumType.getMethod("fromValue", String.class);
                    return enumType.cast(fromValueMethod.invoke(null, source));
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    // 无fromValue方法时,回退到枚举常量名匹配
                    return Enum.valueOf(enumType, source.toUpperCase());
                }
            }
        }
    }
}

这个全局转换器会优先调用枚举类中的fromValue方法(即OpenAPI Generator生成的@JsonCreator方法),如果枚举类没有该方法,则回退到默认的枚举常量名匹配逻辑,一次性解决所有枚举的参数转换问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 13:24:55