本地执行 java -classpath $jar $class 时报错:
java.lang.NoSuchMethodError: com.alibaba.fastjson.JSONObject.getOrDefault (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object
可是 $jar 内 maven 配置已打入 fastJson 依赖且未 Provided:
com.alibaba fastjson1.2.76 于是开始踩坑之旅。
二.问题分析val json = JSON.parseObject(info) val array = JSON.parseArray(json.getOrDefault("data", "[]").toString).toArray().map(_.toString)我的代码大致为 Json 解析,先解析 Object 再解析 array,由于报错位置提示为 noSuchMethod: getOrDefault,所以说明 json.parseObject 这行执行没有问题,即 fastJson 依赖正常打入,所以可以判断不是因为 maven 未打入依赖造成。所以可能是如下问题:
jar 包冲突: 多个项目都存在 fastJson 依赖,代码读取了低版本的 fastJson,低版本无该方法导致调用失败。这里其实涉及一个常识问题,如果报错 NoClassDefFound 报错,那么大概率是打包失败或者未提供相关 jar 包,而 noSucnMethod 报错除了方法名写错的低级失误外,大部分是 jar 包冲突导致。
三.问题解决 1.存在高低版本 Jar 包A.jar-fastJson 低版本,B.jar-fastJson 高版本,本地执行程序读取低版本 fastJson 有可能导致上述问题,所以需要排查的是 jar 包中哪些项目包含了 fastJson:
这里可以使用 java -verbose:class,该方法会在控制台打印程序运行加载的类的情况,使用该命令即可查看程序内哪些依赖包含 fastJson,然后再去对应项目查找是否高低版本。
java -verbose:class -classpath your.jar your.class执行后 cat log | grep fastJson 即可看到 fastJson 的文件来自于哪个 jar 包,后方红色标识即为来源:
经过检查,所有 fastJson 类文件均加载于同一 jar 包,即我本身的项目 jar 包依赖,所以排除高低版本问题。
Tips:
这里查看项目依赖采用了 -verbose 方法,该方法除了打印 jvm 运行时加载依赖,也可以传入 gc 或者 jni 查看虚拟机响应,其次也可以借助 maven :
mvn -Dverbose dependency:tree该方法可以按层次打印出jar包相关依赖于版本,可以更好地方便定位 jar 包方法冲突与版本冲突,有需要可以参考我之前的文章: java.lang.NoSuchMethodError 之 依赖冲突解决方案,之前写作本文主要是线上任务出现该报错,本文主要是在本地执行 java 任务报错,所以虽然场景不同,但是报错相同,两篇文章的方法都可以借鉴到排查该方法背后的 jar 包冲突。
2.maven 依赖存在问题
既然不是高低版本问题,那就定位到唯一 jar 包,我怀疑是 maven 打包异常,所以决定 provided 该依赖,随后从外部传入。
首先注释掉 jar 包中的 fastJson 依赖:
com.alibaba fastjson1.2.76 provided 随后本地执行传入 fastJson 依赖,本地传入依赖可以使用 -Djava.ext.dirs 参数,该方法指定一个路径文件夹,文件夹下包含所以项目需要的额外依赖,有点类似项目中的 lib 文件夹:
java -verbose:class -Djava.ext.dirs=$dir -classpath your.jar your.class这里在本地创建一个文件夹放入 fastJson 依赖即可:
再次执行任务,依旧出现同样问题,因此唯一 jar 包的问题也不存在了。
3.Java 环境问题(解决 )方法1高低版本排除了多 jar 包的情况,方法二单独 provided 排除了单 jar 包的情况,所以剩下的只剩环境问题了,回想起刚才 -verbose 打印的日志,java 版本都是 1.7.0:
查看本地 Java 环境:
echo $JAVA_HOME /usr/local/jdk1.8.0_131原来是 java 版本不匹配,修改提交脚本再次尝试,问题解决:
$JAVA_HOME/bin/java -classpath your.jar your.class四.总结
这个问题困扰了一天,期间多半时间花在 maven 打包问题排查与 fastJson 依赖冲突的问题上,但是结果是最基本的 java 环境不匹配问题。今日踩坑,明日避坑,虽然期间尝试了多种方法最终解决方法如此简单,但是找到简单方法过程中,熟悉了不同的 jar 包冲突分析方法,后续再有类似问题也可以更快的定位和解决,所以还是收获满满,可能这就是学习的魅力吧,最后希望大家都可以少点 bug ~



