今天在项目中,发现报了java.lang.NoSuchMethodError这个错误 ,错误信息以下:
Caused by: java.lang.NoSuchMethodError: com.google.common.base.Objects.firstNonNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
at com.google.common.cache.CacheBuilder.getKeyStrength(CacheBuilder.java:529)java
根据异常信息咱们大概能够了解,工程中引用了一个名叫 com.google.common.cache.CacheBuilder 的类,并调用了其中名为 getKeyStrength 的方法,以下:web
Strength getKeyStrength() { return (Strength)Objects.firstNonNull(this.keyStrength, Strength.STRONG); }
该方法又调用了com.google.common.base.Objects.firstNonNull这个方法,可是系统在加载该方法时却表示没有找到该方法。在IDEA里面输入com.google.common.base.Objects这个类名出来了两个:缓存
点进去发现,guava-14.0.1的com.google.common.base.Objects类实现是有这个方法的,以下:maven
public static <T> T firstNonNull(@Nullable T first, @Nullable T second) { return first != null ? first : Preconditions.checkNotNull(second); }
可是在google-collection-1.0.jar包中的com.google.common.base.Objects却没有这个实现,其内容以下:ide
package com.google.common.base; import com.google.common.annotations.GwtCompatible; import java.util.Arrays; import javax.annotation.Nullable; @GwtCompatible public final class Objects { private Objects() { } public static boolean equal(@Nullable Object a, @Nullable Object b) { return a == b || a != null && a.equals(b); } public static int hashCode(Object... objects) { return Arrays.hashCode(objects); } }
得出结论,这是一个包冲突问题,工具
当遇到这类问题咱们该如何解决呢,主要有如下三步:测试
前面已经分析过,是com.google.common.base.Objects这个类的冲突ui
见前面分析,发现是google-collection-1.0.jar和guava-14.0.1.jar包冲突this
第三步,咱们看 google-collections-1.0.jar 是不是应用直接引用的。google
经过查看这两个包的引用发现,工程里面直接引用了google-collections这个jar包,以下:
<dependency> <groupId>com.google.collections</groupId> <artifactId>google-collections</artifactId> </dependency>
,没有发现直接引用guava.jar包,所以guava.jar包是经过其余jar包间接引用过来的。
咱们的项目是经过 maven 进行引用 jar 包的管理。所以,结合 maven 的命令 mvn dependency:tree 能够发现这两个jar 包究竟是经过哪些jar 包间接引用进来的。
经查询资料发现,guava.jar包是google-collections的升级版,包括后者,因此去掉google-collections的包引入,重启工程,问题解决。
这类状况的发生极可能是由于以下情况引发的:随着业务需求的不断扩展,应用中代码量也会逐渐增加,工程中引用的二方包或者三方包也天然而然会愈来愈多。所以,不可避免,可能存在引用的二方包或三方包相互冲突所致使的系统问题。
通常经过以下方法,能够定位并决绝包冲突的问题:
这个命令能够输出全部的依赖,若是加入一些参数,能够过滤一些东西,如
-Dverbose
-Dincludes
-Dexcludes 等参数会可以帮助尽快定位问题
有时,你觉得解决了,可是恰恰仍是报类包冲突(典型症状是java.lang.ClassNotFoundException或Method不兼容等异常),这时你能够设置一个断点,在断点处经过下面这个我作的工具类来查看Class所来源的JAR包:
package com.ridge.util;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
/**
* @author : chenxh
* @date: 13-10-31
*/
public class ClassLocationUtils {
/**
* 获取类全部的路径
* @param cls
* @return
*/
public static String where(final Class cls) {
if (cls == null)throw new IllegalArgumentException("null input: cls");
URL result = null;
final String clsAsResource = cls.getName().replace('.', '/').concat(".class");
final ProtectionDomain pd = cls.getProtectionDomain();
if (pd != null) {
final CodeSource cs = pd.getCodeSource();
if (cs != null) result = cs.getLocation();
if (result != null) {
if ("file".equals(result.getProtocol())) {
try {
if (result.toExternalForm().endsWith(".jar") ||
result.toExternalForm().endsWith(".zip"))
result = new URL("jar:".concat(result.toExternalForm())
.concat("!/").concat(clsAsResource));
else if (new File(result.getFile()).isDirectory())
result = new URL(result, clsAsResource);
}
catch (MalformedURLException ignore) {}
}
}
}
if (result == null) {
final ClassLoader clsLoader = cls.getClassLoader();
result = clsLoader != null ?
clsLoader.getResource(clsAsResource) :
ClassLoader.getSystemResource(clsAsResource);
}
return result.toString();
}
}
随便写一个测试,设置好断点,在执行到断点处按alt+F8动态执行代码(intelij idea),假设咱们输入:
Java代码 收藏代码
ClassLocationUtils.where(org.objectweb.asm.ClassVisitor.class)
便可立刻查出类对应的JAR了:
这就是org.objectweb.asm.ClassVisitor类在运行期对应的JAR包,若是这个JAR包版本不是你指望你,就说明是你的IDE缓存形成的,这时建议你Reimport一下maven列表就能够了,以下所示(idea):
(1)Reimport一下,IDE会强制根据新的pom.xml设置从新分析并加载依赖类包,以获得和pom.xml设置相同的依赖。
(2)idea清除缓存,采用idea自带的功能,File->Invalidate Caches 功能直接完成清除idea cache
参考文献:http://fufeng.iteye.com/blog/1755167
http://blog.csdn.net/sun_wangdong/article/details/51852113