apache / servicecomb-java-chassis

ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features
Apache License 2.0
1.91k stars 813 forks source link

从CSE 1.X 升级到 CSE 2.X后,接口配置的swagger注解@ApiImplicitParams 参数失效 #4166

Open JedrekWang opened 10 months ago

JedrekWang commented 10 months ago

问题背景:

从CSE 1.X 升级到 CSE 2.X后,接口配置的swagger注解@ApiImplicitParams 参数失效 接口定义如下:

@RequestMapping(path = "/v1/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams(value = {
        @ApiImplicitParam(name = "x-test-header", dataType = "string", required = false,
            paramType = "header", value = "xxx",
            allowableValues = "true,false")})
    public String testV1(HttpServletRequest request) {
        return "ok";
    }

使用CSE 1.X时,如果传入的header不是true或者false,报错如下:

{
    "message": "Parameter is not valid for operation [XXX.XXX.testV1]. Parameter is [x-test-header]. Processor is [header]."
}

使用CSE 3.X时,接口无报错

问题分析:

通过对比CSE 1.X和2.X的代码,发现org.apache.servicecomb.common.rest.codec.RestCodec#restToArgs将request请求转发为请求对象的过程中,org.apache.servicecomb.common.rest.definition.RestOperationMeta#init中创建Type的代码进行了调整 从

    Method method = operationMeta.getMethod();
    Type[] genericParamTypes = method.getGenericParameterTypes();

调整为

(Type)operationMeta.getSwaggerProducerOperation().getSwaggerParameterTypes().get(parameter.getName())

导致type丢失了枚举信息

请帮忙确认是否需要跟CSE 1.X保持兼容以及其他类似注解是否有相同问题

liubao68 commented 10 months ago

Validation是针对method的, 这个机制是一直未变化的。

1.x之所有发生了校验, 应该是swagger生成代码导致的, 这个刚刚撞上了。 不应该作为兼容性问题处理。 业务使用的时候,如果需要参数校验,一定需要注意参数校验是针对 method 声明来的,非声明的参数是不会发生校验的。

liubao68 commented 9 months ago

1.x 对于 ApiImplicitParam 的 allowableValues 会生成类型: cse.gen.springmvctest.springmvc.ApiImplicitParamsSchema.Enum_180c67426bd12add66bac48181939b7d9467d64a0a0eeea4604059a9af50c7d1 报错是将输出转换为这个Enum的时候。 2.x没有代码生成机制,所以这个不生效了。 这个场景非常生僻,建议对于参数校验,使用 Validation API。 swagger api只用来描述接口。

上述接口和预期行为等价于下面的用法:

  public enum Tokens {
    TRUE,
    FALSE
  }

@RequestMapping(path = "/v1/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String testV1(@RequestHeader("x-test-header") Tokens token) {
        return "ok";
    }

总结: @ApiImplicitParam 定义的参数只有swagger类型信息,没有Java类型信息。 如果需要依赖于Java类型信息进行参数校验,必须显示的在接口声明该参数。