升级依赖之后程序为什么会抛 NoSuchMethodError?二进制兼容和源码兼容是一回事吗?工具说「兼容」就一定能跑吗?这篇做了 15 种 API 变化,用工具和真实客户端互相对照。
C1 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('method', 'old', 'REMOVED')]
C2 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('method', 'size', 'MODIFIED')]
C3 状态 MODIFIED binaryCompatible=true sourceCompatible=true 变化:[('method', 'b', 'NEW')]
C6 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('method', 'm', 'MODIFIED')]
C7 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[]
C9 状态 MODIFIED binaryCompatible=true sourceCompatible=false 变化:[('method', 'io', 'MODIFIED')]
I4 状态 MODIFIED binaryCompatible=true sourceCompatible=false 变化:[('method', 'stop', 'NEW')]
I5 状态 MODIFIED binaryCompatible=true sourceCompatible=true 变化:[('method', 'stop', 'NEW')]
C11 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('method', 's', 'MODIFIED')]
C12 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('field', 'f', 'MODIFIED')]
C14 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('method', 'm', 'REMOVED'), ('method', 'm', 'NEW')]
C15 状态 REMOVED binaryCompatible=false sourceCompatible=false 变化:[('constructor', 'C15', 'REMOVED'), ('method', 'x', 'REMOVED')]
p.C8 状态 MODIFIED binaryCompatible=false sourceCompatible=false 变化:[('method', 'hidden', 'MODIFIED')]
--semantic-versioning --report-only-summary 的输出: ['1.0.0']
常量 K 的实际行为:对 2.0 重新编译的 K10 输出 2 ;japicmp 的报告里 C10 没有出现任何变化客户端 在 1.0 上运行 换成 2.0 jar 运行 对 2.0 重新编译 K1 2 抛出 java.lang.NoSuchMethodError: 'int C1.old()' 编译失败:cannot find symbol ← 删除方法 old() K2 1 抛出 java.lang.NoSuchMethodError: 'int C2.size()' 编译失败:incompatible types: possible lossy conversion from long to int ← 返回类型 int → long K3 1 1 通过 ← 新增方法 b() K4 ok 抛出 java.lang.AbstractMethodError: Receiver class K4$Impl does not define or inherit an implementation of the 编译失败:Impl is not abstract and does not override abstract method stop() in I ← 接口新增抽象方法 stop() K5 ok ok 通过 ← 接口新增 default 方法 stop() K6 5 抛出 java.lang.IncompatibleClassChangeError: class K6$Sub overrides final method C6.m()I 编译失败:m() in Sub cannot override m() in C6 ← 方法变 final(客户端子类覆盖它) K7 1 抛出 java.lang.IncompatibleClassChangeError: class K7$Sub cannot inherit from final class C7 编译失败:cannot inherit from final C7 ← 类变 final(客户端子类继承它) K8 1 抛出 java.lang.IllegalAccessError: class K8 tried to access method 'int p.C8.hidden()' (K8 and p.C8 are in unn 编译失败:hidden() is not public in C8; cannot be accessed from outside package ← public 方法变包级私有 K9 ok ok 编译失败:unreported exception IOException; must be caught or declared to be thr ← 方法新增 throws IOException K10 1 1 通过 ← 常量 K 从 1 改为 2 K11 1 抛出 java.lang.IncompatibleClassChangeError: Expected static method 'int C11.s()' 编译失败:non-static method s() cannot be referenced from a static context ← static 方法变实例方法 K12 7 抛出 java.lang.NoSuchFieldError: Class C12 does not have member field 'int f' 编译失败:incompatible types: possible lossy conversion from long to int ← 字段 int → long K13 1 1 通过 ← 方法加 @Deprecated K14 3 抛出 java.lang.NoSuchMethodError: 'int C14.m(int)' 通过 ← 参数 int → long K15 1 抛出 java.lang.NoClassDefFoundError: C15 编译失败:cannot find symbol ← 整个类 C15 被删除