我将一个Java库打包为JAR,当我试图从它调用方法时,它抛出许多Java .lang. incompatibleclasschangeerror。这些错误似乎是随机出现的。什么样的问题会导致这个错误?


当前回答

如果这是此错误可能发生的记录,则:

我刚刚在WAS(8.5.0.1)上得到了这个错误,在CXF(2.6.0)加载spring (3.1.1_release)配置期间,BeanInstantiationException卷起一个CXF ExtensionException,卷起一个IncompatibleClassChangeError。下面的代码片段显示了堆栈跟踪的要点:

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.bus.spring.SpringBus]: Constructor threw exception; nested exception is org.apache.cxf.bus.extension.ExtensionException
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
            at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
            ... 116 more
Caused by: org.apache.cxf.bus.extension.ExtensionException
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:167)
            at org.apache.cxf.bus.extension.Extension.getClassObject(Extension.java:179)
            at org.apache.cxf.bus.extension.ExtensionManagerImpl.activateAllByType(ExtensionManagerImpl.java:138)
            at org.apache.cxf.bus.extension.ExtensionManagerBus.<init>(ExtensionManagerBus.java:131)
            [etc...]
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
            ... 118 more

Caused by: java.lang.IncompatibleClassChangeError: 
org.apache.neethi.AssertionBuilderFactory
            at java.lang.ClassLoader.defineClassImpl(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:284)
            [etc...]
            at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:586)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:658)
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:163)
            ... 128 more

在这种情况下,解决方案是改变war文件中模块的类路径顺序。也就是说,在WAS控制台中打开战争应用程序,并选择客户端模块。在模块配置中,将类加载设置为“parent last”。

在WAS控制台中可以找到:

应用程序->应用程序类型-> WebSphere企业应用程序 单击代表应用程序的链接(war) 点击“模块”区域下的“模块管理” 单击底层模块的链接 将“类装入器顺序”更改为“(父类最后)”。

其他回答

While these answers are all correct, resolving the problem is often more difficult. It's generally the result of two mildly different versions of the same dependency on the classpath, and is almost always caused by either a different superclass than was originally compiled against being on the classpath or some import of the transitive closure being different, but generally at class instantiation and constructor invocation. (After successful class loading and ctor invocation, you'll get NoSuchMethodException or whatnot.)

如果这种行为看起来是随机的,那么它很可能是多线程程序类根据最先遇到的代码加载不同的传递依赖项的结果。

要解决这些问题,请尝试使用-verbose作为参数启动VM,然后查看异常发生时正在加载的类。你应该会看到一些令人惊讶的信息。例如,拥有相同依赖项的多个副本,以及您从未预料到的版本,或者如果您知道它们被包括在内,您就不会接受这些版本。

用Maven解决重复的jar最好是结合Maven下的Maven - Dependency - Plugin和Maven -enforcer- Plugin(或SBT的Dependency Graph Plugin),然后将这些jar添加到顶级POM的一部分或作为SBT中的导入依赖元素(以删除这些依赖)。

好运!

如果这是此错误可能发生的记录,则:

我刚刚在WAS(8.5.0.1)上得到了这个错误,在CXF(2.6.0)加载spring (3.1.1_release)配置期间,BeanInstantiationException卷起一个CXF ExtensionException,卷起一个IncompatibleClassChangeError。下面的代码片段显示了堆栈跟踪的要点:

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.bus.spring.SpringBus]: Constructor threw exception; nested exception is org.apache.cxf.bus.extension.ExtensionException
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
            at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
            ... 116 more
Caused by: org.apache.cxf.bus.extension.ExtensionException
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:167)
            at org.apache.cxf.bus.extension.Extension.getClassObject(Extension.java:179)
            at org.apache.cxf.bus.extension.ExtensionManagerImpl.activateAllByType(ExtensionManagerImpl.java:138)
            at org.apache.cxf.bus.extension.ExtensionManagerBus.<init>(ExtensionManagerBus.java:131)
            [etc...]
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
            ... 118 more

Caused by: java.lang.IncompatibleClassChangeError: 
org.apache.neethi.AssertionBuilderFactory
            at java.lang.ClassLoader.defineClassImpl(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:284)
            [etc...]
            at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:586)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:658)
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:163)
            ... 128 more

在这种情况下,解决方案是改变war文件中模块的类路径顺序。也就是说,在WAS控制台中打开战争应用程序,并选择客户端模块。在模块配置中,将类加载设置为“parent last”。

在WAS控制台中可以找到:

应用程序->应用程序类型-> WebSphere企业应用程序 单击代表应用程序的链接(war) 点击“模块”区域下的“模块管理” 单击底层模块的链接 将“类装入器顺序”更改为“(父类最后)”。

请检查你的代码是否由两个具有相同类名和包定义的模块项目组成。例如,如果有人使用复制粘贴来创建基于先前实现的接口的新实现,就会发生这种情况。

I have a web application that deploys perfectly fine on my local machine's tomcat(8.0.20). However, when I put it into the qa environment (tomcat - 8.0.20), it kept on giving me the IncompatibleClassChangeError and it was complaining that I was extending on an interface. This interface was changed to an abstract class. And I compiled the parent and child classes and still I kept on getting the same issue. Finally, I wanted to debug, so, I changed the version on the parent to x.0.1-SNAPSHOT and then compiled everything and now it is working. If someone is still hitting the problem after following the answers given here, please make sure the versions in your pom.xml are also correct. Change the versions to see if that works. If so, then fix the version problem.

新打包的库与旧版本不向后二进制兼容(BC)。由于这个原因,一些没有重新编译的库客户端可能会抛出异常。

这是一个完整的Java库API更改列表,这些更改可能会导致使用旧版本库构建的客户端在运行新版本库时抛出Java .lang. incompatibleclasschangeerror(即破坏BC):

非终场变为静态, 非常数场变成非静态场, 类变成接口, 接口变成类, 如果你添加了一个新的字段到类/接口(或者添加了一个新的超类/超接口),那么一个来自客户端类C的超接口的静态字段可能会隐藏一个从C的超类继承的添加的字段(具有相同的名称)(非常罕见的情况)。

注意:还有许多其他由其他不兼容的更改引起的异常:NoSuchFieldError, NoSuchMethodError, IllegalAccessError, InstantiationError, VerifyError, NoClassDefFoundError和AbstractMethodError。

关于BC更好的论文是由Jim des Rivières撰写的“进化基于java的API 2:实现API二进制兼容性”。

还有一些自动工具可以检测这些变化:

japi-compliance-checker clirr japitools sigtest japi-checker

在你的库中使用日语遵从检查器:

japi-compliance-checker OLD.jar NEW.jar

clir工具的使用:

java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jar

好运!