API tooling is about controlling API Evolution and Version Numbering.
Read Achieving API Binary Compatibility for understanding the various incompatibilities.
The following API incompatibilities have been explained in more detail below :
Adding an API field to an API class that is extended by Clients is dangerous in two respects:
Example - Adding a Field to Class
public class Base {String h = "Base";} public class Derived extends Base { } public class Test { public static void main(String[] args) { String s = new Derived().h; System.out.println(s); } }
This program produces the output:
BaseSuppose that a public static field h is added to Derived
:
public class Derived extends Base { public static String h = "humongous"; }
If Derived
is recompiled but not Test
, then running the new binary with the existing binary for Test
will cause an IncompatibleClassChangeError
.
Furthermore, if char type h is added to Derived instead, there would be compilation error.
Apart from the binary compatibility issues, it is generally good software engineering practice that API classes should not expose any non-constant fields.
Adding an API field to an API interface that is implemented by Clients is dangerous in two respects:
Adding a default method will break an existing client type if it already implements another interface that declares a default method with a matching signature, and the client type already refers to the default method from the other interface (except when using the Interface.super.method() notation). The added default method will cause an IncompatibleClassChangeError at run time, see JLS8 13.5.6. Furthermore, re-compiling the type will result in a compile error.
Example - Adding A Default Method
API public interface interfaceAPI {} Client Code public interface clientInterface { default void doSomething() { System.out.println("Do something client...") ; } } public class ClientCode implements clientInterface, interfaceAPI { public static void main(String[] args) { new ClientCode().doSomething(); } }
This program produces the output:
Do something client...Suppose that a default method is added to interfaceAPI
:
public interface interfaceAPI { default void doSomething() { System.out.println("Do something API..."); } }
If interfaceAPI
is recompiled but not ClientCode
, then running the new binary with the existing binary for ClientCode
will cause an IncompatibleClassChangeError
.