openapi-generator-maven-plugin 添加引号到枚举,swagger-ui 使用它们导致错误。

huangapple go评论52阅读模式
英文:

openapi-generator-maven-plugin adds quotes to enumeration and swagger-ui uses them causing error

问题

以下是您提供的内容的翻译部分:

我们有如下定义的服务:

    openapi: "3.0.0"
    info:
      version: 1.0.0
      title: UVZ Reg
    paths:
      /enumerationRequestApproval/{requestId}/{approvalStatus}:
        post:
          tags: 
            - EnumerationApprovalController
          parameters:
           - in: path
             name: requestId
             schema:
               type: integer
               format: int64
             required: true
           - in: path
             name: approvalStatus
             schema:
               $ref: "#/components/schemas/enumerationApprovalStatusEnum"
             required: true
          responses:
            200:
              description: status of enumeration approval changed
    components:
      schemas:
        enumerationApprovalStatusEnum:
          type: string
          enum:
            - WAITING_APPROVAL
            - APPROVED
            - NOT_APPROVED

借助 openapi-generator-maven-plugin,我们生成了 Spring Boot 服务:

    @javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2020-07-30T09:35:26.969160+02:00[Europe/Bratislava]")
    
    @Validated
    @Api(value = "enumerationRequestApproval", description = "the enumerationRequestApproval API")
    public interface EnumerationRequestApprovalApi {
    
        default Optional<NativeWebRequest> getRequest() {
            return Optional.empty();
        }
    
        /**
         * POST /enumerationRequestApproval/{requestId}/{approvalStatus}
         *
         * @param requestId  (required)
         * @param approvalStatus  (required)
         * @return status of enumeration approval changed (status code 200)
         */
        @ApiOperation(value = "", nickname = "enumerationRequestApprovalRequestIdApprovalStatusPost", notes = "", tags={ "EnumerationApprovalController", })
        @ApiResponses(value = { 
            @ApiResponse(code = 200, message = "status of enumeration approval changed") })
        @RequestMapping(value = "/enumerationRequestApproval/{requestId}/{approvalStatus}",
            method = RequestMethod.POST)
        default ResponseEntity<Void> enumerationRequestApprovalRequestIdApprovalStatusPost(@ApiParam(value = "") @PathVariable("requestId") Long requestId,@ApiParam(value = "",required=true, allowableValues = "WAITING_APPROVAL, APPROVED, NOT_APPROVED") @PathVariable("approvalStatus") EnumerationApprovalStatusEnum approvalStatus) {
            return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    
        }
    
    }

现在,当我们尝试从 Swagger UI(http://localhost:8080/swagger-ui)调用服务时,会失败:

    org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.annotations.ApiParam @org.springframework.web.bind.annotation.PathVariable sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum] for value '"WAITING_APPROVAL"'; nested exception is java.lang.IllegalArgumentException: No enum constant sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum."WAITING_APPROVAL"
    ...

很明显,问题出在枚举值周围的引号上。当我将

    allowableValues = "\"WAITING_APPROVAL\", \"APPROVED\", \"NOT_APPROVED\")

更改为

    allowableValues = "WAITING_APPROVAL, APPROVED, NOT_APPROVED")

一切正常,但由于是生成的 API,我无法手动更改它。这是设计时 API 的外观(无引号):

[![API shown in Visual studio plugin, without quotes][1]][1]

这是部署时 API 的外观(添加引号):

[![API shown in deployed swagger-ui, with quotes][2]][2]

我已经测试了以下内容:
- openapi-generator-maven-plugin 版本 4.2.3 和 4.3.1。
- springfox-swagger-ui 2.9.2 和 3.0.0(springfox-boot-starter maven artifact)。

这个问题是 openapi-generator-maven-plugin、swagger-ui 还是我的 OpenApi3 定义的问题?我该如何修复它以使其正常工作?

[1]: https://i.stack.imgur.com/gWJwB.png
[2]: https://i.stack.imgur.com/ZVXh4.png
英文:

We have service defined like:

openapi: &quot;3.0.0&quot;
info:
version: 1.0.0
title: UVZ Reg
paths:
/enumerationRequestApproval/{requestId}/{approvalStatus}:
post:
tags: 
- EnumerationApprovalController
parameters:
- in: path
name: requestId
schema:
type: integer
format: int64
required: true
- in: path
name: approvalStatus
schema:
$ref: &quot;#/components/schemas/enumerationApprovalStatusEnum&quot;
required: true
responses:
200:
description: status of enumeration approval changed
components:
schemas:
enumerationApprovalStatusEnum:
type: string
enum:
- WAITING_APPROVAL
- APPROVED
- NOT_APPROVED

With help of openapi-generator-maven-plugin we generate spring boot service:

@javax.annotation.Generated(value = &quot;org.openapitools.codegen.languages.SpringCodegen&quot;, date = &quot;2020-07-30T09:35:26.969160+02:00[Europe/Bratislava]&quot;)
@Validated
@Api(value = &quot;enumerationRequestApproval&quot;, description = &quot;the enumerationRequestApproval API&quot;)
public interface EnumerationRequestApprovalApi {
default Optional&lt;NativeWebRequest&gt; getRequest() {
return Optional.empty();
}
/**
* POST /enumerationRequestApproval/{requestId}/{approvalStatus}
*
* @param requestId  (required)
* @param approvalStatus  (required)
* @return status of enumeration approval changed (status code 200)
*/
@ApiOperation(value = &quot;&quot;, nickname = &quot;enumerationRequestApprovalRequestIdApprovalStatusPost&quot;, notes = &quot;&quot;, tags={ &quot;EnumerationApprovalController&quot;, })
@ApiResponses(value = { 
@ApiResponse(code = 200, message = &quot;status of enumeration approval changed&quot;) })
@RequestMapping(value = &quot;/enumerationRequestApproval/{requestId}/{approvalStatus}&quot;,
method = RequestMethod.POST)
default ResponseEntity&lt;Void&gt; enumerationRequestApprovalRequestIdApprovalStatusPost(@ApiParam(value = &quot;&quot;,required=true) @PathVariable(&quot;requestId&quot;) Long requestId,@ApiParam(value = &quot;&quot;,required=true, allowableValues = &quot;\&quot;WAITING_APPROVAL\&quot;, \&quot;APPROVED\&quot;, \&quot;NOT_APPROVED\&quot;&quot;) @PathVariable(&quot;approvalStatus&quot;) EnumerationApprovalStatusEnum approvalStatus) {
return new ResponseEntity&lt;&gt;(HttpStatus.NOT_IMPLEMENTED);
}
}

Now when we try to call service from swagger-ui (http://localhost:8080/swagger-ui) it will fail:

org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type &#39;java.lang.String&#39; to required type &#39;sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum&#39;; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.annotations.ApiParam @org.springframework.web.bind.annotation.PathVariable sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum] for value &#39;&quot;WAITING_APPROVAL&quot;&#39;; nested exception is java.lang.IllegalArgumentException: No enum constant sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum.&quot;WAITING_APPROVAL&quot;
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:133)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at sk.uvzsr.is.reg.config.CorsFilter.doFilter(CorsFilter.java:43)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.annotations.ApiParam @org.springframework.web.bind.annotation.PathVariable sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum] for value &#39;&quot;WAITING_APPROVAL&quot;&#39;; nested exception is java.lang.IllegalArgumentException: No enum constant sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum.&quot;WAITING_APPROVAL&quot;
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:129)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:73)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:693)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:125)
... 50 more
Caused by: java.lang.IllegalArgumentException: No enum constant sk.uvzsr.is.reg.be.rest.model.EnumerationApprovalStatusEnum.&quot;WAITING_APPROVAL&quot;
at java.base/java.lang.Enum.valueOf(Enum.java:266)
at org.springframework.core.convert.support.StringToEnumConverterFactory$StringToEnum.convert(StringToEnumConverterFactory.java:52)
at org.springframework.core.convert.support.StringToEnumConverterFactory$StringToEnum.convert(StringToEnumConverterFactory.java:38)
at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:436)
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
... 56 more

It is clear problem is with quotes around enumeration value. When I changed

allowableValues = &quot;\&quot;WAITING_APPROVAL\&quot;, \&quot;APPROVED\&quot;, \&quot;NOT_APPROVED\&quot;&quot;)

to

allowableValues = &quot;WAITING_APPROVAL, APPROVED, NOT_APPROVED&quot;)

everything works, but since it is generated API I cannot change it manually every time.

This is how API looks while in design (no quotes):
openapi-generator-maven-plugin 添加引号到枚举,swagger-ui 使用它们导致错误。
This is how API looks deployed (quotes added):
openapi-generator-maven-plugin 添加引号到枚举,swagger-ui 使用它们导致错误。

I tested this with

  • openapi-generator-maven-plugin version 4.2.3 and 4.3.1.
  • springfox-swagger-ui 2.9.2 and 3.0.0 (springfox-boot-starter maven artifact)

Is this problem with openapi-generator-maven-plugin, swagger-ui or my OpenApi3 definition? How can I fix this to work?

答案1

得分: 2

为了解决这个问题,我们只需要修复实现生成的接口的控制器中不正确的注解@ApiParam。因此,在覆盖和实现生成方法的控制器中,我们使用正确的值指定@ApiParam:

@Override
public ResponseEntity<sk.uvzsr.is.reg.be.rest.model.EnumerationRequest> enumerationRequestApprovalRequestIdApprovalStatusPost(Long requestId, @ApiParam(value = "", required = true, allowableValues = "WAITING_APPROVAL, APPROVED, NOT_APPROVED") @PathVariable("approvalStatus") EnumerationApprovalStatusEnum approvalStatus) {
    // implementation
}
英文:

To fix this we just had to fix the incorrect annotation @ApiParam in controller that implements the generated interface. So in controller where the generated method is overridden and implemented we specify @ApiParam with correct values:

@Override
public ResponseEntity&lt;sk.uvzsr.is.reg.be.rest.model.EnumerationRequest&gt; enumerationRequestApprovalRequestIdApprovalStatusPost(Long requestId, @ApiParam(value = &quot;&quot;,required=true, allowableValues = &quot;WAITING_APPROVAL, APPROVED, NOT_APPROVED&quot;) @PathVariable(&quot;approvalStatus&quot;) EnumerationApprovalStatusEnum approvalStatus) {
// implementation
}

答案2

得分: 2

我们通过自定义openapi-generator maven plugin生成代码的方式来解决了这个问题。我们只是用我们自己的副本替换了默认的pathParams.mustache模板文件,然后在这里我们删除了整个部分{{#allowableValues}} ..... {{/allowableValues}}

这导致在生成的控制器方法中,枚举参数不再具有allowableValues。之后,swagger-ui正确显示它。

有关mustache模板自定义的更多信息:openapi-generator自定义

英文:

We fixed this by customizing the way how openapi-generator maven plugin generates the code. We just replaced default pathParams.mustache template file by our own copy and here we just removed whole part {{#allowableValues}} ..... {{/allowableValues}}

this causes that in generated controller method there are no more allowableValues for enum params. After this, swagger-ui shows it correctly.

more info about mustache template customisation: openapi-generator customisation

huangapple
  • 本文由 发表于 2020年7月30日 16:14:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/63168945.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定