解决java.lang.IncompatibleClassChangeError

今天整理了Maven的pom.xml文件后,把多个项目用maven集成在了一起,结果在启动Tomcat的时候,遇到一个奇葩的错误:

严重: Servlet [spring] in web application [/AbcWeb] threw load() exception
java.lang.IncompatibleClassChangeError: class org.springframework.core.type.classreading.ClassMetadataReadingVisitor has interface org.springframework.asm.ClassVisitor as super class
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2495)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:859)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1301)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1166)
	at java.lang.ClassLoader.defineClass1(Native Method)

重启Tomcat,Project>Clean都玩遍了,也没找到问题在哪里。。。于是Google之,结果从这个页面里找到了这样一段话:

Your newly packaged library is not backward binary compatible (BC) with old version. For this reason some of the library clients that are not recompiled may throw the exception.

This is a complete list of changes in Java library API that may cause clients built with an old version of the library to throw java.lang.IncompatibleClassChangeError if they run on a new one (i.e. breaking BC):

  1. Non-final field become static,

  2. Non-constant field become non-static,

  3. Class become interface,

  4. Interface become class,

  5. if you add a new field to class/interface (or add new super-class/super-interface) then a static field from a super-interface of a client class C may hide an added field (with the same name) inherited from the super-class of C (very rare case).

其实,细心一点可以发现,错误描述其实很清晰了:

java.lang.IncompatibleClassChangeError: class org.springframework.core.type.classreading.ClassMetadataReadingVisitor has interface org.springframework.asm.ClassVisitor as super class

意思是说,有个叫ClassMetadataReadingVisitor的类,以一个叫ClassVisitor的接口作为父类了。但是大家都知道,Java中类和接口的关系只能是实现,而不是继承。那么为什么会出现这个类呢?我尝试着在Eclipse中打开这个报错的类:

171126_KhCm_1434710.png

可以看到,我的Workspace中可以发现两个版本(3.2.6和4.0.0)的ClassMetadataReadingVisitor类,分别打开这两个类(Maven会自动下载源代码),可以看到类的声明均为:

class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata

于是我又打开错误描述中提到的ClassVisitor这个类,结果却是这样的:

171701_7Zs7_1434710.png

可以看到,Eclipse在Workspace中发现了3个这样的类,而且包名类名都完全一样。可以看到,在spring的3.1.4版本中,这个叫ClassVisitor的类其实是一个接口,这个接口被放在spring-asm模块中。而在3.2.6和4.0.0版本中,这个ClassVisitor就变成了一个抽象类。

发现这个差别后,我检查了我的spring-core模块的版本:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.2.6</version>
</dependency>

但同时我的pom.xml中还有这样一个包的依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-asm</artifactId>
    <version>3.1.4.RELEASE</version>
</dependency>

正好这个3.1.4的接口就在Workspace中,于是这两个包当中都有这个ClassVisitor,删掉spring-asm模块后,错误消失,问题解决。

这个spring-asm包也不知道什么时候导入的,这就告诉我们:

  1. 在使用Maven处理依赖包的时候,一定不要随便乱添加依赖,用到的包才导入,没用到包的声明要及时删掉。

  2. 在整合多个maven项目的时候,要注意依赖包的版本,因为有些类(可能包含有的字段)在不同的版本中声明可能会不同,错误的类或字段声明将导致IncompatibleClassChangeError。


参考页面:

http://stackoverflow.com/questions/1980452/what-causes-java-lang-incompatibleclasschangeerror

转载于:https://my.oschina.net/itblog/blog/528613

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值