最近在改一份二手代碼的時候,項目運行報了個java.lang.IllegalArgumentException: node to traverse cannot be null異常。
WTF?!難道我HQL寫錯了?!我只是添加了一個update方法而已啊!java
這裏使用的是JPA的Query註解,其實語法跟HQL是同樣的,我已經把這行HQL每一個空格都TM檢查過了,沒有發現任何奇怪的東西,沒辦法了只好調試一下源碼node
最早拋出異常的是在Hibernate的orghibernatehqlinternalastutilNodeTraverser.java:46,這裏判斷若是AST爲空,則拋出異常,那AST究竟是個啥啊?
經過跟蹤NodeTraverser的調用,可看到ACT是從parser獲取的,而這裏的parser實際上就是Hibernate的Hql語法分析器!所以網上不少文章都會得出本文提到的異常就是HQL語法錯誤致使的了。可是我這個HQL明顯沒有語法錯誤的,問題又出在哪呢?咱們加個短點瞧一瞧:spa
好玩的事情來了,若是HQL是select開頭的話,是不會報錯的hibernate
等到一條update了,果真parser處理後的hqlAst是空的對比上面Select語句就能夠明顯看出問題所在了:問題出在了parser.statement()裏,那跟進去看看囖:
逐行調試,發如今執行updateStatement()時拋出異常,再跟進去:
跑到default去了調試
由於LA(1)是41,不在switch的任何分支裏,而後實際上我在這花了不少時間,都浪費在看antrl的源碼上了,就是想搞明白LA是在那裏設值的,結果越看越懵逼,但實際上咱們能夠換個思路,經過監控每一步執行後的各個變量能夠發現有這樣的規律:ip
上圖是在執行match(UPDATE)前,各個主要變量如圖所示源碼
直到執行了match方法後,LA(1)變爲了41,而同時,LT(1)裏的值引發了個人注意:
上面已經提到過了,實際上這部分代碼是Hibernate的HQL語法解析器,那講道理的話,第一次執行,處理完UPDATE關鍵字,日後應該是第二個關鍵字,而實際上咱們的HQL中根被沒有order這個詞啊,爲何會致使報錯呢?
還記得上面的某個斷點麼,就是調用parser.statement()的地方,來看看交由parser處理時的hql是什麼樣子的it
大家發現問題了嗎?Hibernate在處理hql的時候,是會把包名補全的,而這個實體類的包名是以order開頭的!update關鍵字後不能有order關鍵字...io