使用OpenAPI Generator生成响应式代码时ServerWebExchange无法实例化
问题排查:Spring WebFlux + OpenAPI Generator 接口调用报错
错误日志
2022-08-05 14:23:41.257 ERROR 22404 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.web.server.ServerWebExchange] with root cause java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.web.server.ServerWebExchange at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:267) ~[spring-beans-5.3.21.jar:5.3.21] ...
环境与配置
- 环境:spring-boot v2.7.1、openjdk-17
- OpenAPI Generator Maven插件配置:
<plugin> <groupId>org.openapitools</groupId> <artifactId>openapi-generator-maven-plugin</artifactId> <version>6.0.1</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <inputSpec>${project.basedir}/src/main/resources/api/petstore.yml</inputSpec> <generatorName>spring</generatorName> <output>${project.build.directory}/generated-sources/swagger</output> <modelNameSuffix>DTO</modelNameSuffix> <generateSupportingFiles>true</generateSupportingFiles> <supportingFilesToGenerate> ApiUtil.java </supportingFilesToGenerate> <configOptions> <reactive>true</reactive> <delegatePattern>false</delegatePattern> <library>spring-boot</library> <dateLibrary>java8</dateLibrary> <interfaceOnly>true</interfaceOnly> <performBeanValidation>true</performBeanValidation> <useOptional>true</useOptional> </configOptions> </configuration> </execution> </executions> </plugin>
生成的接口代码片段
@RequestMapping( method = RequestMethod.GET, value = "/pet/{petId}", produces = { "application/json", "application/xml" } ) default Mono<ResponseEntity<PetDTO>> getPetById( @Parameter(name = "petId", description = "ID of pet to return", required = true) @PathVariable("petId") Long petId, @Parameter(hidden = true) final ServerWebExchange exchange ) { Mono<Void> result = Mono.empty(); exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); for (MediaType mediaType : exchange.getRequest().getHeaders().getAccept()) { if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { String exampleString = "{ \"photoUrls\" : [ \"photoUrls\", \"photoUrls\" ], \"name\" : \"doggie\", \"id\" : 10, \"category\" : { \"name\" : \"Dogs\", \"id\" : 1 }, \"tags\" : [ { \"name\" : \"name\", \"id\" : 0 }, { \"name\" : \"name\", \"id\" : 0 } ], \"status\" : \"available\" }"; result = ApiUtil.getExampleResponse(exchange, mediaType, exampleString); break; } if (mediaType.isCompatibleWith(MediaType.valueOf("application/xml"))) { String exampleString = "<pet> <id>10</id> <name>doggie</name> <photoUrls> <photoUrls>aeiou</photoUrls> </photoUrls> <tags> </tags> <status>aeiou</status> </pet>"; result = ApiUtil.getExampleResponse(exchange, mediaType, exampleString); break; } } return result.then(Mono.empty()); }
控制器实现
@RestController public class PetController implements PetApi { }
问题原因
- 参数注入规则不匹配:
ServerWebExchange是Spring WebFlux核心接口,需通过@Context注解标记才能被正确注入。生成的接口直接将其作为方法参数,Spring会尝试实例化接口,而接口无可用构造器,因此抛出异常。 - 注解环境冲突:生成的接口使用了Spring MVC的
@RequestMapping注解,而非WebFlux对应注解,导致Servlet栈的DispatcherServlet尝试处理WebFlux类型参数,加剧了解析失败。
解决方案
方案1:修改生成配置,移除ServerWebExchange参数
在OpenAPI Generator的configOptions中添加<serverWebExchange>false</serverWebExchange>,禁止生成包含该参数的方法:
<configOptions> <reactive>true</reactive> <delegatePattern>false</delegatePattern> <library>spring-boot</library> <dateLibrary>java8</dateLibrary> <interfaceOnly>true</interfaceOnly> <performBeanValidation>true</performBeanValidation> <useOptional>true</useOptional> <serverWebExchange>false</serverWebExchange> <!-- 新增配置 --> </configOptions>
重新生成代码后,接口方法不再包含ServerWebExchange参数,即可正常调用。
方案2:手动添加@Context注解(临时方案)
若业务需保留ServerWebExchange参数,可在生成的接口方法参数上添加@Context注解:
default Mono<ResponseEntity<PetDTO>> getPetById( @Parameter(name = "petId", description = "ID of pet to return", required = true) @PathVariable("petId") Long petId, @Parameter(hidden = true) @org.springframework.web.bind.annotation.Context final ServerWebExchange exchange ) { // 原有代码逻辑 }
注意:此方法需每次生成代码后手动修改,仅适合临时测试场景。
方案3:升级OpenAPI Generator版本
OpenAPI Generator 6.0.1存在WebFlux适配缺陷,升级至6.6.0及以上版本后,生成的代码会自动适配WebFlux的注解与参数注入规则,避免此类问题。
内容的提问来源于stack exchange,提问作者Mate Szilard
相关产品推荐
相关产品推荐

