奔驰戴克300cswagger3设置值可以为空_Swagger异常定位纪实,是⽤的不
对,还是Swagger。。。
前⾔
swagger ui是⼀个采⽤注解驱动的接⼝⽂档⼯具,⽬前已⽀持标准的open api v3规范协议,所以不仅可以在java项⽬⾥使⽤,每个语⾔都有相应的open api实现。项⽬集成swagger后,可以⽣成导出open api v3格式化的元数据集,有了这个接⼝元数据,你可以在任何⽀持
v3协议的ui上展⽰你的api信息。在前后端分离的项⽬中,swagger ui的出现,⼤⼤提⾼了前后端联调的效率。swagger ui在解析注解标注的元数据信息时,特别场景下会抛异常,⽽且抛的异常没有直观的有价值的异常信息,所以深⼊的debug了⼀番,虽然最后问题解决很简单,但是过程⾮常曲折。故将bug定位过程记录在此。汽车出租
异常信息
这个异常只会在加载swagger-ui的页⾯时会抛出,每次刷新页⾯,获取⼀次api接⼝就会触发⼀次异常。
异常分析
丰田avensis@JsonProperty("x-example")
public Object getExample() {
if (example == null) {
return null;
}
try {
if (BaseIntegerProperty.TYPE.equals(type)) {
return Long.valueOf(example);
} else if (DecimalProperty.TYPE.equals(type)) {
return Double.valueOf(example);
} else if (BooleanProperty.TYPE.equals(type)) {
if ("true".equalsIgnoreCase(example) || "false".equalsIgnoreCase(defaultValue)) {
return Boolean.valueOf(example);
}
}
} catch (NumberFormatException e) {
LOGGER.warn(String.format("Illegal DefaultValue %s for parameter type %s", defaultValue, type), e);
}
return example;
}
如上是异常相关的代码。从异常信息表象来看,是⼀个强转导致的问题,代码试图将⼀个空的字符串转换成数值类型导致异常抛出。并且是getExample时抛出的异常,这⾥需要了解swagger ui的加载过
程和基础架构才能直接定位。swagger中的example是为了在⽣成的api doc中,给出相关字段的调⽤⽰例,并在触发接⼝调⽤时,默认⾃动填充example的值。这⾥显然是哪个地⽅的example设置不合理导致的异常。那么,接下来要做的就是到这个空字符串的原始代码。
debug到真实原因
借助IDEA的debug功能,点击异常后⾯的create breakpoint,在触发异常的地⽅打上断点。触发异常,进⼊断点,获取到了关键信息
⼀个被描述为app id的字段,⽤这个信息全局搜索,得到如下的结果:
中北镇凯迪拉克
有三个相关的Model实体,⾸先,这三个Model的appId字段都没有设置过example属性,所以,到这⼀步,可以先下⼀个⼩的结论,不是我们设置的example导致的问题,默认在不设置的情况下,example的默认值就是空字符串。然后肯定只有其中⼀个有问题,因为异常只会触发⼀次。在不知道结果情况下,依次对这三个Model的appId字段加上正确的example描述,经测试,只有GetAppBannerRequestDTO 加上时,异常才消失,罪魁祸⾸就是它了。但是,为什么呢?其他两个Model为啥就没有问题呢?在博主交叉测验后,发现了最终的原因。
结论及注意事项
小电跑
当Model作⽤于请求的接收参数时,并且请求的类型为GET,那么Swagger Ui会⾃动收集Model所有属性的examole参数,因为这个参数是字符串类型,所以会做⼀个类型转换动作。当字段类型为数值类型,⼜有没⼿动设置example的值,那么Swagger框架拿到的是个空字符串,强转空字符串就抛异常了。⽽如果请求是POST,就不会触发这段逻辑,所以同为携带数值类型DTO的ImgReplaceRequestDTO没有问题。如果不是接收参数,作为响应参数,也不会触发这段逻辑,故⽽AppBannerResponseVO也就没有问题了。所以,需要注意的就是当DTO作⽤于GET请求的接收参数时,切记给所有的数值类型加上正确的example属性
后记
博主认为这⾥属于⼀个设计缺陷,⽽不是我们的使⽤问题。在获取example的逻辑⾥,第⼀段代码就判断了example是否为null。这表明了example有可能为空,但是默认值却设置了⼀个空字符串。代表不⼿动将example设置为null,这段判null返回的逻辑就永远跑不到,⽽且没⼈会这么做,⼿动给example设置为null。况且,在触发异常的这种场景下,框架不能强制使⽤者设置example这种操作。在github仓库追踪这块代码发现,⽬前Swagger ui已经迈⼊了3.x版本,全⾯基于open api v3协议规范设计。所以,这部分代码完全不⼀样了。⽽存档的1.5x版本这个问题依旧。
jeep牧马人油耗下⾯是3.x的处理⽅式,虽然example的默认值还是“”。但是通过NotBlank判断了下,所以不会触发异常了
为啥不直接升级3.x?
3.x版本既然已经修复了,为啥不直接升级到3.x版本呢?可能有⼈会有这个疑问。Swagger3.x版本属于⼀个⼤跨度的迭代版本,和之前的版本完全不兼容,3.x主要⾯向了open api v3规范协议设计实现,注解实体等模型都是⼀⼀对应的。⽽在这个版本之前的1.5x系列版本是Swagger⾃⼰设计的api模型。所以代码层上⾯完全不兼容,升级的⼯作量会⾮常⼤。不过,新项⽬还是推荐使⽤3.x版本,这个版本的api 数据更通⽤。可以根据api的数据⽣成各种语⾔的客户端包。就像proto⽣成客户端包⼀样。