我将一个Java库打包为JAR,当我试图从它调用方法时,它抛出许多Java .lang. incompatibleclasschangeerror。这些错误似乎是随机出现的。什么样的问题会导致这个错误?
当前回答
如果你使用scala和sbt和scala-logging作为依赖项,那么这可能会发生,因为scala-logging的早期版本的名称是scala-logging-api.因此,本质上依赖项解析不会发生,因为不同的名称会导致启动scala应用程序时的运行时错误。
其他回答
这个问题的另一个原因是,如果你为Android Studio启用了即时运行。
修复
如果发现开始出现此错误,请关闭“立即运行”。
Android Studio主要设置 构建、执行、部署 即时运行 取消勾选“启用即时运行…”
Why
即时运行在开发过程中修改了大量的东西,以使它更快地提供更新到您的运行应用程序。因此,即时运行。当它起作用时,它真的很有用。然而,当出现这样的问题时,最好的办法是关闭即时运行,直到Android Studio发布下一个版本。
如果你使用scala和sbt和scala-logging作为依赖项,那么这可能会发生,因为scala-logging的早期版本的名称是scala-logging-api.因此,本质上依赖项解析不会发生,因为不同的名称会导致启动scala应用程序时的运行时错误。
我遇到了同样的问题,后来我发现我是在Java版本1.4上运行应用程序,而应用程序是在版本6上编译的。
实际上,这是因为有一个重复的库,一个位于类路径中,另一个包含在位于类路径中的jar文件中。
如果这是此错误可能发生的记录,则:
我刚刚在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中的导入依赖元素(以删除这些依赖)。
好运!
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap