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


当前回答

新打包的库与旧版本不向后二进制兼容(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

好运!

其他回答

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

这意味着您已经对库进行了一些不兼容的二进制更改,而无需重新编译客户端代码。Java语言规范§13详细描述了所有这些更改,最突出的是将非静态的非私有字段/方法更改为静态或反之亦然。

根据新的库重新编译客户端代码,应该就可以开始了。

更新:如果你发布了一个公共库,你应该尽可能避免做出不兼容的二进制更改,以保持所谓的“二进制向后兼容性”。单独更新依赖jar在理想情况下不会破坏应用程序或构建。如果你不得不打破二进制向后兼容性,建议增加主版本号(例如从1.x。Y到2.0.0),然后发布更改。

新打包的库与旧版本不向后二进制兼容(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

好运!

我在与玻璃鱼的战争中反复部署时遇到过这个问题。我的班级结构是这样的,

public interface A{
}

public class AImpl implements A{
}

它被改成了

public abstract class A{
}

public class AImpl extends A{
}

在停止并重新启动域之后,结果很好。 我用的是glassfish 3.1.43

在浪费了太多时间后记录下另一个场景。

确保您的依赖jar中没有包含带有EJB注释的类。

我们有一个普通的jar文件,它有一个@local注释。这个类后来从这个公共项目移到我们的主ejb jar项目中。ejb jar和公共jar都捆绑在ear中。我们的公共jar依赖项的版本没有更新。因此,两个类试图成为具有不兼容的更改的东西。