實際開發中遇到java.lang.NoSuchMethodError
在開發中遇到java.lang.NoSuchMethodError的錯誤。
java.lang.NoSuchMethodError: com.sinosoft.ims.api.kernel.dto.RequestPrpDuserDto.getCodeMethod()Ljava/lang/String; at com.sinosoft.ims.core.kernel.service.impl.PrpDuserServiceImpl.queryHandler1CodeInfo(PrpDuserServiceImpl.java:127) at com.sinosoft.ims.core.kernel.service.impl.PrpDuserServiceImpl$$FastClassBySpringCGLIB$$5429f8a0.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
看到這個錯誤,首先想到有沒有這個方法,要是沒有就加上。但是程式碼中是存在的,重新編譯執行還是報同樣的錯誤。
錯誤可能的原因:
- 有這個類,該類真的沒有這個方法
- 有這個類,但是改方法出現問題,也是會出現這個bug
- 有這個類,而且有好幾個,他們之間發生了衝突
在部落格中看到一篇解決辦法,還是不錯的。下面是我的具體的解決方法:
原因排除:
1、點選進入報錯的程式碼所在行,在報錯的地方打一個debug點,重行啟動專案或重現該錯誤,讓程式執行到打斷點的該行程式碼,別往下執行,繼續第2步:
2、開啟display介面(若沒有,請在window--show view裡面找出該介面),
手動敲出xxx.class.getProtectionDomain().getCodeSource(),xxx為報錯的類的全類名,滑鼠選中敲出的該行程式碼,然後點選介面右上角的J圖示,即會打印出到該類對應的包所在的地址。如下圖所示。
可以看到,結果為:
(java.security.CodeSource) (file:/D:/Program%20Files%20(x86)/eclipse/configuration/org.eclipse.osgi/843/0/.cp/lib/core-3.1.1.jar <no signer certificates>)
PS:若是其他錯誤也會在此提示出來。
3、接著複製該類的全類名,快捷鍵Ctrl+Shift+T開啟open type介面,檢視我們的專案引用到的包中,哪些有這個類:
我們發現有兩個包中有org.eclipse.jdt.internal.compiler.Compiler這個類,分別為:
包一:ecj.3.5.1.jar
包二:core-3.1.1.jar
地址分別為:
但我們發現,剛剛在display中,我們看到的地址,居然不是來自這上面兩個地址(上面兩個包的地址都在C盤,DEBUG中的包來自D盤),也就是說,實現執行環境引入的包,並不是在我們自己專案中配置的,因為open typy只能找到自己專案中配的東西。
那麼D盤的這個包,在什麼地方引入的呢?
想想,這個錯誤是在專案啟動時報的,那麼除了專案,還有“伺服器”可能會引入其他包,那麼有沒有可能是伺服器幫我們引入呢?
4、開啟伺服器的Classpath,可以找到伺服器確實引入了這個包
那麼我們在伺服器的classpath中把這個包“remove”掉。
5、再次重新啟動專案,dubug、卡點、display,這次結果如下:
發現:實際環境中,現在己經沒有引入D盤那個core-3.1.1.jar包了。我們讓專案執行下去,發現還是報同樣的錯——找不到方法。那麼接下來我們讓專案引用ecj.3.5.1.jar這個包試試。
6、ctrl+shift+T、雙擊進入core-3.1.1.jar中Compiler類所在的目錄結構:
提示:左邊欄勾上這個標誌,即可展開該包所在的目錄:
同理,開啟ecj.3.5.1.jar中Compiler類所在的目錄結構。
最後發現,這個jar包都同一個專案下面,而且兩個包都有Compiler類,且排在前面的是core-3.1.1.jar,但是core-3.1.1.jar的Compiler類並沒有我們想要的方法,所以報錯了。但是eclipse在找類的時候,只要按順序找到一個,就不會往下找了,所以排在下面的ecj-3.5.1.jar並不會被找到,即使裡面有Compiler這個類,且有我們想要的方法。
7、排除core-3.1.1.jar包:
該專案是maven專案。我們嘗試直接在該專案的pom.xml中搜索core這個包是搜尋不到的,那麼這個core-3.1.1包可能是因為本專案引入其他專案,而其他專案引入core-3.1.1.jar,所以本專案間接把該包引過來了。
同時,因為該專案是maven專案,可以通過以下該方法排除這個包:
排除後,該專案的pom.xml變成:
假如是非maven專案,那麼可以直接從lib中除去該包,或從專案根目錄下面開啟.classpath檔案,找到對應的包的配置,刪除該行即可。
通過該pom.xml我們可以知道,之所以會產生jar包衝突,原因有兩個:
1、 本專案A本身引用了ecj-3.5.1.jar包,同時引入了專案B,而專案B引入了core-3.1.1.jar,所以本專案也相當於引入了core-3.1.1.jar,這就是maven專案中常見的jar包衝突。
2、 那為什麼maven沒有自動幫我們解決jar包衝突呢,那是因為ecj-3.5.1.jar包和core-3.1.1.jar包的groupId和artifactId都不一樣,所以maven認為這是兩個jar包,並不衝突,解決的辦法就是像上面那樣,加入exclusions排除。所以我們在開發一個元件的時候,起名字是一個很重要的問題,如果升級元件連名字也改了,使用者會產生很大的不方便。
再次啟動專案,問題解決。
ps:我的專案出現此問題原因是提示報錯行那個方法不能轉換成json,加上了註解,執行第1步和第2步即找到具體報錯原因。