背景
近期參與了一個攻堅項目,前期因為其他流程原因,測試時間已經耽擱了好幾天了,本以為已經解決了卡點,後續流程應該順順利利的,沒想到 人在地鐵上,bug從咚咚來~
沒有任何修改的服務接口,抛出異常:
java.lang.ClassCastException: java.util.HashMap cannot be cast to cn.xxx.xxx.xxx.xxx.BatchInfo
排查過程
1、作為資深寫bug的老司機,第一感覺是傳參的封包格式有問題了,可以通過模拟封包排查。于是乎,在群裡圈了服務提供方同學B看下,BG快速的用測試工具+本地debug的方式,驗證了下封包格式,發現居然都調用成功了。。。
2、同步服務調用同學L,重點關注:1)、調用方的序列化方式;2)、最近代碼改動邏輯是否有問題。L同學确認自己邏輯沒有問題後,同步B同學和S同學,看内部是否有什麼處理邏輯。。。
3、第二天早上一來,快速寫了單測,确認服務端收到的封包格式,的确沒有問題。于是乎,開始扒代碼。。。發現可疑的代碼:
BeanUtils.copyProperties(item,cargoInfo)
private List<CargoInfo> convertToCargoInfo(OutboundEventCallbackRequest outboundEventCallbackRequest) {
return outboundEventCallbackRequest.getCargos().stream().map(item -> {
CargoInfo cargoInfo = new CargoInfo();
BeanUtils.copyProperties(item, cargoInfo);
return cargoInfo;
}).collect(Collectors.toList());
}
PS:用戶端&服務端類關系
因為BeanUtils.copyProperties屬于淺拷貝,而淺拷貝隻是調用子對象的set方法,并沒有将所有屬性拷貝(引用的一個記憶體位址)。是以将在進行調用時,JSF會因為反序列化時找不到對應的類,就會将其轉換為Map。
直覺圖如下:
以上,初步定位原因,解決方式也就清晰了。
解決方案
去掉BeanUtils.copyProperties,進行手動指派。最終解決了這個問題。
後續反思
1、想起王東嶽老師的那句話,越原始的越穩定~
2、如果這種轉換比較多,建議使用MapStruct
3、謹慎使用BeanUtils.copyProperties,請看: