Springfox 3.0.0 遗留的bug及兼容性问题及解决方案

Springfox 3.0.0 中增加了对OpenAPI 3的支持,同时仍默认同时开放Swagger 2的接口。接口地址分别为:

  • OpenAPI 3: \v3\api-docs
  • Swagger 2: \v2\api-docs

因为开发者已经很久没有维护,目前有一些遗留的bug及兼容性问题没有解决,其中有些可以通过有些代码和配置进行绕过。

笔者最近使用SpringdocSpringfox进行替换,整个操作比较简单,主要工作量在于将注解从Swagger 2升级到OpenAPI 3,具体操作可以参考Springdoc官方文档 [Migrating from SpringFox](https://springdoc.org/#migrating-from-springfox). 但上游服务及底层依赖库仍在使用Swagger 2生成客户端代码生成,需要Service中保留Swagger 2地址,所以需要将依赖回退到Springfox,但注解仍然使用OpenAPI 3版本,以便未来再次替换回来。

Springfox文档中表明支持OpenAPI 3的注解,可以通过增加@EnableOpenApi,实测下来,除了@OpenAPIDefinition里的文档信息以外,其他基本支持。

部分遗留问题:

不可访问模型

当有些Model类在API规范定义中,但实际方法中没有直接匹配该模型时,可能会报该错误。
注解定义:因为返回值有多种,所以使用了ResponseEntity<Object>,通用错误400返回类DataValidationErrorResponse没有被代码适配,所以报错。

    @Operation(summary = "Decode notification", operationId = "decode-notify", description = "Decode and translate notification to internal format", security = {
        @SecurityRequirement(name = "bearerAuth")}, tags = {"Decode notification"})
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "OK - the request has succeeded.", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(anyOf = {
            PaymentNotificationItem.class, RefundNotificationItem.class}))),
        @ApiResponse(responseCode = "400", description = "Bad Request - request is not well-formed, syntactically incorrect or violates schema.", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = DataValidationErrorResponse.class))),
       })
    @PostMapping(value = "/pay/notify", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<Object> decodeNotify(@Valid @RequestBody String notifyBody) {
        // handler logic
    }

API显示Error-ModelName错误,下为Swagger 2 API 结果:

      "400": {
        "description": "Bad Request - request is not well-formed, syntactically incorrect or violates schema.",
        "schema": {
          "$ref": "Error-ModelName{namespace='com.payments.common.model', name='DataValidationErrorResponse'}",
        },
      },

Swagger 2 API会打出控制台错误信息:
ReferenceModelSpecificationToPropertyConverter - Unable to find a model that matches key ModelKey{qualifiedModelName=ModelName{namespace='com.payments.common.model', name='DataValidationErrorResponse'}, viewDiscriminator=null, validationGroupDiscriminators=[], isResponse=true}

解决方案

SwaggerConfig中加入配置.additionalModels(typeResolver.resolve(DataValidationErrorResponse.class))

    @Bean
    public Docket customImplementation() {
        return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)).paths(PathSelectors.any()).build()
            .additionalModels(typeResolver.resolve(DataValidationErrorResponse.class))
            .securitySchemes(Lists.newArrayList(apiKey(), clientId(), traceId()))
            .securityContexts(Lists.newArrayList(securityContext())).apiInfo(apiInfo());
    }

无效/冗余参数

基本不会影响Swagger UI,Redoc等UI文档生成,但是在Swagger Editor中会报错 should NOT have additional properties

image.png

解决方案

在swagger-core中定义了一些Mixin规则,可以Jackson Mixin配置ObjectMapper从而进行参数过滤。 Springfox默认的依赖没有Swagger-core,在不考虑增加新的依赖的情况下,可以找到对应的Mixin配置,手动加到SwaggerConfig中,然后获取ObjectMapper进行配置。

参考Mixin设置:

代码范例:

这里过滤了Swagger 2里面的originalRef参数,以及重复response项responsesObject,OpenAPI 3里面的exampleSetFlag及extensions数组。

    /**
     * Logic reference: ObjectMapperFactory in swagger-core 1.6.6 & swagger-core 2.2.0
     *
     * @return JacksonModuleRegistrar
     */
    @Bean
    // Remove auto generated additionalProperty
    public JacksonModuleRegistrar swaggerJacksonModuleRegistrar() {
        return objectMapper -> {
            // Swagger 2 cleanup additionalProperty: originalRef
            objectMapper.addMixIn(RefProperty.class, Swagger2Mixin.class);
            objectMapper.addMixIn(RefModel.class, Swagger2Mixin.class);

            // Swagger 2 cleanup additionalProperty: responsesObject
            objectMapper.addMixIn(Operation.class, Swagger2Mixin.class);

            // OAS 3 cleanup additionalProperty: exampleSetFlag & extensions
            objectMapper.addMixIn(Schema.class, Oas3Mixin.class);
            objectMapper.addMixIn(MediaType.class, Oas3Mixin.class);
        };
    }

    /**
     * Swagger 2 cleanup additionalProperty: originalRef & responsesObject
     */
    static abstract class Swagger2Mixin {
        // Swagger 2 Mixin property
        @JsonIgnore
        public abstract String getOriginalRef();

        @JsonIgnore
        public abstract Responses getResponsesObject();
    }

    /**
     * OpenAPI 3 cleanup additionalProperty: exampleSetFlag & extensions
     */
    static abstract class Oas3Mixin {

        @JsonAnyGetter
        public abstract Map<String, Object> getExtensions();

        @JsonIgnore
        public abstract boolean getExampleSetFlag();
    }


作者:戴意伦
链接:https://www.jianshu.com/p/c3f38f7c6e2b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。