关于swagger-AbstractSerializableParameter类的异常问题

项目场景:

今天写接口的时候,本想着用 swagger 去测试,然后看到控制台打印了很多错误日志,大概就是关于 AbstractSerializableParameter 这个类转换时出现了错误,虽然不影响功能,但是看着还是很糟心,在网上相关博客之后,自己总结了一下,避免下次再犯


问题描述

    @PostMapping(value = "/save-bill-info")
    @ApiOperation(value = "保存财务账单信息")
    public ResponseBean saveBillInfo(
            @ApiParam(required = true, value = "商品名称") @RequestParam(required = true) String productTitle,
            @ApiParam(required = true, value = "商品价格") @RequestParam(required = true) BigDecimal price,
            @ApiParam(required = false, value = "商品数量") @RequestParam(required = false) Integer number,
            @ApiParam(required = false, value = "平均人数") @RequestParam(required = false) Integer average,
            @ApiParam(required = true, value = "支付金额") @RequestParam(required = true) BigDecimal payMoney,
            @ApiParam(required = true, value = "支付类型") @RequestParam(required = true) PayTypeEnum payType,
            @ApiParam(required = true, value = "账单类型") @RequestParam(required = true) BillTypeEnum type,
            @ApiParam(required = true, value = "消费日期") @RequestParam(required = true) String day,
            @ApiParam(required = false, value = "财务标签") @RequestParam(required = false) List<Integer> labels,
            @ApiParam(required = false, value = "发送方主键") @RequestParam(required = false) Integer senderId,
            @ApiParam(required = false, value = "接收方主键") @RequestParam(required = false) Integer receiverId
    ) {
    
    
        financeService.saveBillInfo(productTitle,price,number,average,payMoney,payType,type,day,labels,senderId,receiverId);
        return ResponseBean.success();
    }

以上就是我今天定义的接口,启动项目之后打开 swagger 文档

在这里插入图片描述

后面还有很多错误日志,我就只截取了一部分。

原因分析:

点到 AbstractSerializableParameter 源码里面去看,源码如下:

    ...
    protected String example;
    protected String type;
    ...

    @JsonProperty("x-example")
    public Object getExample() {
    
    
        if (this.example == null) {
    
    
            return null;
        } else {
    
    
            try {
    
    
                if ("integer".equals(this.type)) {
    
    
                    return Long.valueOf(this.example);
                }

                if ("number".equals(this.type)) {
    
    
                    return Double.valueOf(this.example);
                }

                if ("boolean".equals(this.type) && ("true".equalsIgnoreCase(this.example) || "false".equalsIgnoreCase(this.defaultValue))) {
    
    
                    return Boolean.valueOf(this.example);
                }
            } catch (NumberFormatException var2) {
    
    
                LOGGER.warn(String.format("Illegal DefaultValue %s for parameter type %s", this.defaultValue, this.type), var2);
            }

            return this.example;
        }
    }

从源码上来看就是拿 type 去解析对应的 example,如果没有解析成功的话就会报 Illegal DefaultValue %s for parameter type %s 这种错误,而且只会校验这三种类型的数据、那么这个 typeexample 是怎么来的呢?

其实在我们通过 swagger 定义接口的时候就已经给出了这些信息,比如之前接口定义的 price 参数:

@ApiParam(required = true, value = "商品价格") @RequestParam(required = true) BigDecimal price,

这个参数其实已经确定了该参数的 typenumber 类型,example 没有定义,取默认的就是 "",可以点击 @ApiParam 注解看到

@Target({
    
    ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiParam {
    
    

    ...

    String example() default "";

    ...
}

也就是说如果我们没有给 integernumberboolean 这三种类型的参数设置 example 的话,程序走到 AbstractSerializableParameter 这个类,就会拿 "" 进行后续的 Long.valueOf(this.example)Double.valueOf(this.example)Boolean.valueOf(this.example) 操作,导致解析出现异常,从而报错。

同理使用 @ApiModelProperty 定义请求体,只要为 integernumberboolean 这三种类型,不设置 example 也一样会报错,比如以下 enableFlag 字段:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "查询菜单列表")
public class QueryMenuListReq extends PageInfo {
    
    

    @ApiModelProperty("关键字")
    private String keyWord;

    @ApiModelProperty("是否禁用")
    private Boolean enableFlag;

}

@ApiModelProperty 源码:

@Target({
    
    ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiModelProperty {
    
    

    ...

    String example() default "";

    ...
}


解决方案:

如果知道它为什么会报错了之后,那就很容易解决了,比如之前定义的接口,我给 IntegerBigDecimalBoolean 所定义的参数设置个 example 不就行了嘛

/save-bill-info 接口中的 IntegerBigDecimal 类型字段设置 example

    @PostMapping(value = "/save-bill-info")
    @ApiOperation(value = "保存财务账单信息")
    public ResponseBean saveBillInfo(
            @ApiParam(required = true, value = "商品名称") @RequestParam(required = true) String productTitle,
            @ApiParam(required = true, value = "商品价格",example = "0") @RequestParam(required = true) BigDecimal price,
            @ApiParam(required = false, value = "商品数量",example = "0") @RequestParam(required = false) Integer number,
            @ApiParam(required = false, value = "平均人数",example = "0") @RequestParam(required = false) Integer average,
            @ApiParam(required = true, value = "支付金额",example = "0") @RequestParam(required = true) BigDecimal payMoney,
            @ApiParam(required = true, value = "支付类型") @RequestParam(required = true) PayTypeEnum payType,
            @ApiParam(required = true, value = "账单类型") @RequestParam(required = true) BillTypeEnum type,
            @ApiParam(required = true, value = "消费日期") @RequestParam(required = true) String day,
            @ApiParam(required = false, value = "财务标签") @RequestParam(required = false) List<Integer> labels,
            @ApiParam(required = false, value = "发送方主键",example = "0") @RequestParam(required = false) Integer senderId,
            @ApiParam(required = false, value = "接收方主键",example = "0") @RequestParam(required = false) Integer receiverId) {
    
    
        financeService.saveBillInfo(productTitle,price,number,average,payMoney,payType,type,day,labels,senderId,receiverId);
        return ResponseBean.success();
    }

QueryMenuListReq 请求体 enableFlag 字段设置 example

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "查询菜单列表")
public class QueryMenuListReq extends PageInfo {
    
    

    @ApiModelProperty("关键字")
    private String keyWord;

    @ApiModelProperty(value = "是否禁用",example = "false")
    private Boolean enableFlag;

}

启动项目,开启 swagger 就不会报错了

在这里插入图片描述

现在虽然错是不会报了,但是这个其实是 swagger-models:1.5.20bug ,在 1.5.21版本已经修改了这个问题 ,所以为了永久解决这个问题就只能直接去修改 pom 文件中的依赖了, 通过替换依赖解决

之前的依赖:

        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-spring-web</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

修改后的依赖:

        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-spring-web</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <exclusions>
                <exclusion>
                    <groupId>io.swagger</groupId>
                    <artifactId>swagger-models</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

现在不用去设置什么 example 也不会报错了。

在这里插入图片描述

参考博客:
关于Swagger会报AbstractSerializableParameter类的异常问题
解决swagger的类型转换报错问题

猜你喜欢

转载自blog.csdn.net/xhmico/article/details/125643706