1. 程式人生 > >實際開發中遇到java.lang.NoSuchMethodError

實際開發中遇到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)

看到這個錯誤,首先想到有沒有這個方法,要是沒有就加上。但是程式碼中是存在的,重新編譯執行還是報同樣的錯誤。

錯誤可能的原因

  1. 有這個類,該類真的沒有這個方法
  2. 有這個類,但是改方法出現問題,也是會出現這個bug
  3. 有這個類,而且有好幾個,他們之間發生了衝突

在部落格中看到一篇解決辦法,還是不錯的。下面是我的具體的解決方法:

原因排除

  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這個包試試。

  6ctrl+shift+T、雙擊進入core-3.1.1.jarCompiler類所在的目錄結構:

提示:左邊欄勾上這個標誌,即可展開該包所在的目錄:



同理,開啟ecj.3.5.1.jarCompiler類所在的目錄結構。

  最後發現,這個jar包都同一個專案下面,而且兩個包都有Compiler類,且排在前面的是core-3.1.1.jar,但是core-3.1.1.jarCompiler類並沒有我們想要的方法,所以報錯。但是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包的groupIdartifactId都不一樣,所以maven認為這是兩個jar包,並不衝突,解決的辦法就是像上面那樣,加入exclusions排除。所以我們在開發一個元件的時候,起名字是一個很重要的問題,如果升級元件連名字也改了,使用者會產生很大的不方便。

  再次啟動專案,問題解決。


ps:我的專案出現此問題原因是提示報錯行那個方法不能轉換成json,加上了註解,執行第1步和第2步即找到具體報錯原因。