今天陽光明媚,掐指一算,今天比較適合划水。
於是早上到公司之後先是蹲了廁所,然後就準備翻閱公眾號推文。
看的正嗨,突然釘釘群裡開始響了,
生產日誌群報了一條警告,如下:
報錯資訊很明確
UnsupportedOperationException
java.lang.UnsupportedOperationException
at java.util.AbstractMap.put(AbstractMap.java:209)
at com.ifugle.rap.dsb.bot.service.messageBus.chatResult.postProcessor.BizCategoryResultResolveProcessor.concatBizCategoryChatResult(BizCategoryResultResolveProcessor.java:98)
定位到業務程式碼如下
/**
* 拼接業務多輪聊天結果
*
* @param utterance
* @param chatResult
*/
private void concatBizCategoryChatResult(String utterance, Map<String, Object> chatResult) {
Object botAction = bizCategoryChatResult.get(MESSAGE_BOT_ACTION);
if (NullUtil.isNotNull(botAction)) {
chatResult.put(MESSAGE_BOT_ACTION, botAction);//--->這行程式碼報錯
chatResult.put(DISPLAY_CONTENT, bizCategoryChatResult.get(DISPLAY_CONTENT));
chatResult.put(MESSAGE_BOT_FRAMEWORK, bizCategoryChatResult.get(MESSAGE_BOT_FRAMEWORK));
}
}
一個普普通通的map的put操作,怎麼就報錯了呢?繼續往下看。
報錯是在AbstractMap,翻看原始碼
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
這個抽象累定義了一個public的put方法,但是裡面是直接丟擲了異常。
分析一下,應該是某個類繼承了AbstractMap這個類,但是又沒有重寫put方法,於是就直接呼叫了父類的put方法導致直接拋異常了。
我又翻看了阿里雲上的日誌發現傳過來的這個map是一個空的。
我的第一反應就是集合工具類Collections裡面的靜態方法emptyMap(),因為我們業務程式碼中有很多地方都用到了這個。
這裡貼一小段程式碼
if (!continueSendToRobot) {
chatResult = toManResult.getResult();
if (chatResult == null) {
chatResult = EMPTY_CHAT_RESULT;//<---- 看到這個EMPTY_CHAT_RESULT沒
}
chatMessageForm.setChatResult(chatResult);
return ExitHandle.class;
}
這個是個靜態變數,於是我又找到了定義它的地方
// 空的聊天內容
Map<String, Object> EMPTY_CHAT_RESULT = Collections.emptyMap();
繼續看這個emptyMap()
public static final <K,V> Map<K,V> emptyMap() {
return (Map<K,V>) EMPTY_MAP;
}
//又是一個靜態變數
//繼續看
public static final Map EMPTY_MAP = new EmptyMap<>();
//這裡是new了一個EmptyMap物件
//繼續看這個物件,如果這個物件是繼承了AbstractMap恰好它沒有重寫put方法的話,那就證明我的猜想每問題
private static class EmptyMap<K,V> extends AbstractMap<K,V> implements Serializable
//可以看到這個EmptyMap是Collections的一個靜態內部類,繼承了AbstractMap
再看看這個類的所有方法
可以看到該類並沒有重寫put方法!
破案了!
那麼問題來了,怎麼解決呢?
後面我在業務程式碼裡面加了一個判斷邏輯,當這個map是AbstractMap並且是一個空map時,重新給他new一個HashMap。
錯誤示範請勿參考!
/**
* 拼接業務多輪聊天結果
*
* @param utterance
* @param chatResult
*/
private void concatBizCategoryChatResult(String utterance, Map<String, Object> chatResult) {
// 新加程式碼
if (NullUtil.isNull(chatResult) && chatResult instanceof AbstractMap) {
chatResult = new HashMap<>();
}
Object botAction = bizCategoryChatResult.get(MESSAGE_BOT_ACTION);
if (NullUtil.isNotNull(botAction)) {
chatResult.put(MESSAGE_BOT_ACTION, botAction);//--->這行程式碼報錯
chatResult.put(DISPLAY_CONTENT, bizCategoryChatResult.get(DISPLAY_CONTENT));
chatResult.put(MESSAGE_BOT_FRAMEWORK, bizCategoryChatResult.get(MESSAGE_BOT_FRAMEWORK));
}
}
至此,問題就解決啦~~
繼續划水。
更新一下,非常感謝@mrfangzheng在評論裡面的指正,我上面這種BUG的修復方案是錯誤的,學習了謝謝!
我現在的解決方案就是把這個map返回回去,也是這位老哥給的建議,再次感謝。
修正版如下
/**
* 拼接業務多輪聊天結果
*
* @param utterance
* @param chatResult
*/
private Map<String, Object> concatBizCategoryChatResult(String utterance, Map<String, Object> chatResult) {
// 新加程式碼
if (NullUtil.isNull(chatResult) && chatResult instanceof AbstractMap) {
chatResult = new HashMap<>();
}
Object botAction = bizCategoryChatResult.get(MESSAGE_BOT_ACTION);
if (NullUtil.isNotNull(botAction)) {
chatResult.put(MESSAGE_BOT_ACTION, botAction);//--->這行程式碼報錯
chatResult.put(DISPLAY_CONTENT, bizCategoryChatResult.get(DISPLAY_CONTENT));
chatResult.put(MESSAGE_BOT_FRAMEWORK, bizCategoryChatResult.get(MESSAGE_BOT_FRAMEWORK));
}
return chatResult;
}