Zom*_*ies 212 java runtime-error jar binary-compatibility
我将Java库打包为JAR,java.lang.IncompatibleClassChangeError当我尝试从中调用方法时,它会抛出很多s.这些错误似乎是随机出现的.什么类型的问题可能导致此错误?
not*_*oop 167
这意味着您已对库进行了一些不兼容的二进制更改,而无需重新编译客户端代码. Java语言规范§13详细说明了所有此类更改,最突出的是,将static非非私有字段/方法更改为static反之亦然.
针对新库重新编译客户端代码,您应该很高兴.
更新:如果您发布公共库,则应尽可能避免进行不兼容的二进制更改,以保留所谓的"二进制向后兼容性".理想情况下,单独更新依赖关系jar不应该破坏应用程序或构建.如果必须打破二进制向后兼容性,建议在发布更改之前增加主要版本号(例如从1.xy到2.0.0).
lin*_*ild 96
您新打包的库与旧版本不是后向二进制兼容(BC).因此,一些未重新编译的库客户端可能会抛出异常.
这是Java库API中的更改的完整列表,可能导致使用旧版本库构建的客户端抛出java.lang.IncompatibleClassChangeError如果它们在新的上运行(即破坏BC):
注意:由于其他不兼容的更改而导致许多其他异常:NoSuchFieldError,NoSuchMethodError,IllegalAccessError,InstantiationError,VerifyError,NoClassDefFoundError和AbstractMethodError.
关于BC的更好的论文是"发展基于Java的API 2:实现API二进制兼容性",由JimdesRivières撰写.
还有一些自动工具可以检测到这些变化:
使用japi-compliance-checker为您的图书馆:
japi-compliance-checker OLD.jar NEW.jar
Run Code Online (Sandbox Code Playgroud)
clirr工具的用法:
java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jar
Run Code Online (Sandbox Code Playgroud)
祝好运!
Bri*_*ing 57
虽然这些答案都是正确的,但解决问题往往更加困难.它通常是类路径上相同依赖关系的两个稍微不同版本的结果,并且几乎总是由不同于最初编译的超类导致在类路径上或传递闭包的某些导入是不同的,但通常在类实例化和构造函数调用.(成功加载类和ctor之后,你会得到NoSuchMethodException或不知道.)
如果行为看起来是随机的,那么很可能是多线程程序根据首先命中的代码加载不同的传递依赖性的结果.
要解决这些问题,请尝试使用-verbose作为参数启动VM ,然后查看发生异常时正在加载的类.你应该看到一些令人惊讶的信息.例如,拥有相同依赖项和版本的多个副本,如果您知道它们被包含在内,则您从未预料到或将会接受这些副本.
使用Maven解决重复的jar文件最好使用Maven下的maven-dependency-plugin和maven-enforcer-plugin(或SBT的Dependency Graph Plugin,然后将这些jar添加到顶级POM的一部分或作为导入的依赖项) SBT中的元素(删除那些依赖项).
祝好运!
我还发现,当使用JNI从C ++调用Java方法时,如果以错误的顺序将参数传递给调用的Java方法,则在尝试使用被调用方法内部的参数时会出现此错误(因为它们不会是正确的类型)。最初让我感到吃惊的是,在您调用该方法时,JNI不会在类签名检查中为您执行此检查,但是我认为它们不会进行这种检查,因为您可能要传递多态参数,并且它们必须假设你知道自己在做什么。
示例C ++ JNI代码:
void invokeFooDoSomething() {
jobject javaFred = FredFactory::getFred(); // Get a Fred jobject
jobject javaFoo = FooFactory::getFoo(); // Get a Foo jobject
jobject javaBar = FooFactory::getBar(); // Get a Bar jobject
jmethodID methodID = getDoSomethingMethodId() // Get the JNI Method ID
jniEnv->CallVoidMethod(javaFoo,
methodID,
javaFred, // Woops! I switched the Fred and Bar parameters!
javaBar);
// << Insert error handling code here to discover the JNI Exception >>
// ... This is where the IncompatibleClassChangeError will show up.
}
Run Code Online (Sandbox Code Playgroud)
示例Java代码:
class Bar { ... }
class Fred {
public int size() { ... }
}
class Foo {
public void doSomething(Fred aFred, Bar anotherObject) {
if (name.size() > 0) { // Will throw a cryptic java.lang.IncompatibleClassChangeError
// Do some stuff...
}
}
}
Run Code Online (Sandbox Code Playgroud)
我有同样的问题,后来我发现我在Java版本1.4上运行应用程序,而应用程序是在版本6上编译的.
实际上,原因是有一个重复的库,一个位于类路径中,另一个包含在位于类路径中的jar文件中.
| 归档时间: |
|
| 查看次数: |
275246 次 |
| 最近记录: |