1. 程式人生 > 其它 >Java Spring 使用AOP代理方法 型別轉換異常java.lang.ClassCastException 原因及解決辦法

Java Spring 使用AOP代理方法 型別轉換異常java.lang.ClassCastException 原因及解決辦法

技術標籤:notejavaspringaop

有一段程式碼 有時會出現型別轉換異常 很詭異 排查原因發現是spring aop造成的。

專案中我使用了aop進行自定義許可權,若許可權不通過 返回固定的ResponseVo 對應欄位為:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResponseVo<T> {

    @JsonProperty("response_code")
    private Integer responseCode;
    @JsonProperty("verbose_msg")
    private String verboseMsg;

    private T data;
}

為了開發方便 不需要每個controller都寫一個ResponseVo的構建 使用了ResponseBodyAdvice來幫助構建,之前的文章裡寫過

說白了就說Controller方法只需要返回一個任意物件由spring將其封裝到ResponseVo的data欄位中。

下面的是使用ResponseBodyAdvice的效果 上面是正常寫法

這個介面比較簡單可能沒太大對比度

但是在鑑權的aop中 若許可權通過則呼叫方法 返回方法結果

若不通過 則返回內容為:是一個ResponseVo

報錯內容為 不能把ResponseVo轉為BaseInfoVo,且堆疊中看不出任何自己寫的程式碼引用。

測試時發現 有許可權時 這個介面不報錯,沒有許可權時就會報型別轉換異常。找到這個規律 就很容易知道問題出在哪了。

原因是: spring在代理這個方法時 知道這個方法宣告的返回值為BaseInfoVo,但當權限不通過時 我通過切面將其返回值改為了ResponseVo,但R不能轉為B 就會報型別轉換異常。

解決辦法有2種:

1 Controller的返回型別統一為ResponseVo,這樣就沒辦法使用ResponseBodyAdvice了。

2 將方法的返回值宣告為所有可能被返回型別的共同介面:1 Object 因為Object是所有類的父類 2或宣告一個介面由R和Q分別實現 但這樣做意義不大。 缺點是返回值都為Object的話 語義不明確

最終選用了方法1