Swagger異常定位紀實,是用的不對,仍是Swagger自己設計問題

前言

swagger ui是一個採用註解驅動的接口文檔工具,目前已支持標準的open api v3規範協議,因此不只能夠在java項目裏使用,每一個語言都有相應的open api實現。項目集成swagger後,能夠生成導出open api v3格式化的元數據集,有了這個接口元數據,你能夠在任何支持v3協議的ui上展現你的api信息。在先後端分離的項目中,swagger ui的出現,大大提升了先後端聯調的效率。swagger ui在解析註解標註的元數據信息時,特別場景下會拋異常,並且拋的異常沒有直觀的有價值的異常信息,因此深刻的debug了一番,雖然最後問題解決很簡單,可是過程很是曲折。故將bug定位過程記錄在此。java

異常信息

image
這個異常只會在加載swagger-ui的頁面時會拋出,每次刷新頁面,獲取一次api接口就會觸發一次異常。git

異常分析

@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設置不合理致使的異常。那麼,接下來要作的就是找到這個空字符串的原始代碼。github

debug找到真實緣由

藉助IDEA的debug功能,點擊異常後面的create breakpoint,在觸發異常的地方打上斷點。觸發異常,進入斷點,獲取到了關鍵信息
image
一個被描述爲app id的字段,用這個信息全局搜索,獲得以下的結果:
image
有三個相關的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屬性api

後記

博主認爲這裏屬於一個設計缺陷,而不是咱們的使用問題。在獲取example的邏輯裏,第一段代碼就判斷了example是否爲null。這代表了example有可能爲空,可是默認值卻設置了一個空字符串。表明不手動將example設置爲null,這段判null返回的邏輯就永遠跑不到,並且沒人會這麼作,手動給example設置爲null。何況,在觸發異常的這種場景下,框架不能強制使用者設置example這種操做。在github倉庫追蹤這塊代碼發現,目前Swagger ui已經邁入了3.x版本,全面基於open api v3協議規範設計。因此,這部分代碼徹底不同了。而存檔的1.5x版本這個問題依舊。架構

下面是3.x的處理方式,雖然example的默認值仍是「」。可是經過NotBlank判斷了下,因此不會觸發異常了
imageapp

爲啥不直接升級3.x?

3.x版本既然已經修復了,爲啥不直接升級到3.x版本呢?可能有人會有這個疑問。Swagger3.x版本屬於一個大跨度的迭代版本,和以前的版本徹底不兼容,3.x主要面向了open api v3規範協議設計實現,註解實體等模型都是一一對應的。而在這個版本以前的1.5x系列版本是Swagger本身設計的api模型。因此代碼層上面徹底不兼容,升級的工做量會很是大。不過,新項目仍是推薦使用3.x版本,這個版本的api數據更通用。能夠根據api的數據生成各類語言的客戶端包。就像proto生成客戶端包同樣。框架

相關文章
相關標籤/搜索