This appendix describes the rules used by the Signature Test tool API migration feature.
The following sections and tables describe the rules and show whether they break only source compatibility or both source and binary compatibility. Comments and clarifications follow the table for rules that have an asterisk after their number.
Note: A class is called subclassable if it has subclasses outside its package. In other words, this class is not final and has public constructor |
The rules from this group are triggered if the more specific rules from the other groups below are not triggered. For example, adding an interface method defined in rule 2.1, adding constructor in the rule 5.5. In such cases more general rule 1.1 is ignored.
Table C-1 API Migration Compatibility Rules - General
Rule # | Description | Breaks | Severity |
---|---|---|---|
1.1 * |
API (public or protected) type (class, interface, enum, annotation type) or member (method, field) added |
Source |
Warning |
1.2 |
API (public or protected) type (class, interface, enum, annotation type) or member (method, field) removed |
Both |
Severe |
1.3 |
Narrowing type or member visibility - from public to non-public, from protected to package or private |
Both |
Severe |
1.4 * |
Generification of the public API type |
None |
The rules in this group apply to interfaces and annotation types.
Table C-2 API Migration Compatibility Rules - Interfaces and Annotation Types
Rule # | Description | Breaks | Severity |
---|---|---|---|
2.1 |
Add abstract methods |
Both |
Severe |
2.2 |
Add fields |
Both |
Severe |
2.3 * |
Expand the set of superinterfaces (direct or indirect) if the added interface has a field (constant) |
Source |
Warning |
2.4 |
Contract superinterface set (direct or inherited) |
Both |
Severe |
2.5 * |
Add member without default value to annotation type |
Source |
Severe |
2.6 * |
Add member with default value to annotation type |
None |
|
2.7 |
Remove member from annotation type |
Both |
Severe |
2.8 |
Remove default value from member of annotation type |
Both |
Severe |
The rules in this group apply to interfaces and class methods.
Note: Some rules in this group apply only for class methods. |
Table C-3 API Migration Compatibility Rules - Interfaces and Class Methods
Rule # | Description | Breaks | Severity |
---|---|---|---|
3.1 |
Change signature and/or return type |
Both |
Severe |
3.2 |
Change last parameter from array type T[] to variable array T... |
None |
|
3.3 |
Change last parameter from array T... to array type T[] |
Source |
Severe |
3.4 |
Change normalized throw list |
Source |
Severe |
3.5 |
Decrease access from public to protected |
Both |
Severe |
3.6 * |
Increase access from protected to public if the class is subclassable |
Source |
Warning |
3.7 |
Change method from abstract to non-abstract |
None |
|
3.8 |
Change method from non-abstract to abstract (if the class can be subclassed) |
Both |
Severe |
3.9 |
Change method from final to non-final |
None |
|
3.10 |
Change method from non-final to final |
Both |
Severe |
3.11 |
Change method from static to non-static |
Both |
Severe |
3.12 |
Change method from non-static to static |
Both |
Severe |
3.13 |
Change method from native to non-native |
None |
|
3.14 |
Change method from non-native to native |
None |
|
3.15 |
Change method from synchronized to non-synchronized |
None |
|
3.16 |
Change method from non-synchronized to synchronized |
None |
The rules in this group apply to interfaces and class methods.
Note: Some rules from this group apply only for class fields |
Table C-4 API Migration Compatibility Rules - Interfaces and Class Fields
Rule # | Description | Breaks | Severity |
---|---|---|---|
4.1 |
Change type |
Both |
Severe |
4.2 |
Change/Remove constant value |
Both |
Warning |
4.3 |
Decrease access |
Both |
Severe |
4.4 |
Increase access |
None |
|
4.5 |
Change from final to non-final |
None |
|
4.6 |
Change from non-final to final |
Both |
Severe |
4.7 |
Change from static to non-static |
Bone |
Severe |
4.8 |
Change from non-static to static |
Both |
Severe |
The rules in this group apply to classes.
Table C-5 API Migration Compatibility Rules - General
Rule # | Description | Breaks | Severity |
---|---|---|---|
5.1 * |
Add non-abstract and non-static methods |
Both |
Warning |
5.2 |
Add abstract methods (if the class can be subclassed) |
Both |
Severe |
5.3 |
Add static methods (if the class can be subclassed) |
Both |
Warning |
5.4 |
Remove constructors |
Both |
Severe |
5.5 |
Add first constructor with arguments or throws clause |
Both |
Severe |
5.6 |
Add fields |
Both |
Severe |
5.7 |
Expand implemented interface set (direct or indirect) |
||
5.7.1 |
The added interface adds abstract methods |
Both |
Severe |
5.7.2 |
The new interface adds fields or inner classes |
Source |
Severe |
5.7.3 |
If 5.7.1 and 5.7.3 are not true |
None |
|
5.8 |
Contract implemented interface set (direct or indirect) |
Both |
Severe |
5.9 |
Expand superclass set (direct or indirect) |
||
5.9.1 |
Add superclass adds abstract method (see rules 5.1 - 5.3) |
||
5.9.2 |
Add superclass adds field (see rule 5.6) |
||
5.9.3 |
Other cases |
||
5.10 |
Contract superclass set (direct or indirect) |
Both |
Severe |
5.11 |
Change abstract to non-abstract |
None |
|
5.12 |
Change non-abstract to abstract (if the class can be subclassed) |
Both |
Severe |
5.13 |
Change final to non-final |
None |
|
5.14 |
Change non-final to final |
Both |
Severe |
The following sections contain comments and clarifications that make the rules more clear.
Adding a class can theoretically break source code compatibility because new classes can be incorrectly resolved in an existing client's code with type-import-on-demand declarations (also know as wildcard imports). This can happen if the code uses another type with the same simple name. For example:
//client's code import com.acme.*; import com.client.*; ..... Policy p = new Policy(); // this is com.client.Policy .....
In this case, after adding class com.acme.Policy
, the compiler raises the error
reference to Policy is ambiguous, both class com.acme.Policy in com.acme and class com.client.Policy in com.client match.
This rule is considered a warning because it will probably not affect binary compatibility and adhering to this rule makes API evolution very difficult.
Generics are a facility of generic programming that was added to the Java programming language as part of Java SE version 5.0. Generics allow a type or method to operate on objects of various types while providing compile-time type safety. Generification upgrades types using support to-be-specified-later types that are instantiated as needed for specific types that are provided as type parameters.
The Java programming language implements generics using erasure, which ensures that legacy and generic versions usually generate identical class files, except for some auxiliary information about types. Binary compatibility is not broken because it is possible to replace a legacy class file with a generic class file without changing or recompiling any client code.
To facilitate interfacing with non-generic legacy code, it is also possible to use the erasure of a parameterized type as a type. Such a type is called a raw type (Java Language Specification 3/4.8). Allowing the raw type also ensures backward compatibility for source code.
According to this, the following versions of the java.util.Iterator
class are both binary and source code backward compatible:
Class java.util.Iterator
as it is defined in Java SE version 1.4:
public interface Iterator { boolean hasNext(); Object next(); void remove(); }
Class java.util.Iterator
as it is defined in Java SE version 5.0:
public interface Iterator<E> { boolean hasNext(); E next(); void remove(); }
Adding a superinterface with a constant field can shadow another entity with the same simple name. Consider the following code:
public interface Poet{ boolean LITERATE = true; } public interface Playwright{ boolean LITERATE = true; } public interface Shakespeare extends Poet { }
Suppose that a new version of the Shakespeare interface implements interface Playwright as well as Poet as shown here:
public interface Shakespeare extends Poet, Playwright { }
The following client code will not compile because the reference to LITERATE
is ambiguous.
// client code public class ShakespeareImpl implements Shakespeare { void introduce() { System.out.println("Hi, my name is Shakespeare and I'm " + LITERATE ? "quite literate" : "rather illiterate" );} }
The example below shows how adding a member without a default value to an annotation type breaks source code compatibility.
// annotation type v1 @interface Agent{ String name(); } // client's code which uses this annotation type v1 @Agent(name="James Bond") // annotation type v2.1 @interface Agent{ String name(); String id(); // added member } // legacy code is not compilable due to // error - annotation Agent is missing id @Agent(name="James Bond") // annotation type v2.2 @interface Agent{ String name(); String id() default "007"; // added member with default value } // legacy code is compilable @Agent(name="James Bond")
Changing a method from protected to public can break source code compatibility if this method was overridden as protected. In this case the legacy code can not be recompiled because ”access narrowing” is prohibited in the Java programming language. This rule is only a warning because it does not affect binary compatibility, and the probability of its affecting source code compatibility is very low.
Changing or removing constant values can break source code compatibility. For example, consider the following client code example. An integer constant named NOTHING
with a value of 0 is used:
switch (i) { case NOTHING: // some actions case -1: // some other actions }
Assume that the value of the constant NOTHING
is changed from 0 to -1. The client code will not compile because of the duplicate case label. This rule is only a warning because it does not affect binary compatibility, and the probability of its affecting source code compatibility is very low.
Adding a regular method to a subclassable class can break source code and binary compatibility because a subclass can have a method with the same signature but with weaker access privileges. For example consider the following code example:
class ClientClass extends APIClass { private void foo() {} }
Assume that the class APIClass
is changed, and the method
protected void foo() {}
is added. The code cannot be recompiled due of an error that generates the following error message:
foo() in ClientClass cannot override foo() in APIClass; attempting to assign weaker access privileges; was protected
Binary compatibility is broken as defined in JLS 3/3.14.12
Adding a static method to a subclassable class can break source code and binary compatibility, because a subclass can have a method with the same signature. For example consider the following code example:
class ClientClass extends APIClass { protected void foo() {} }
Suppose that the class APIClass
is changed and the method
protected static void foo() {}
is added. The code can not be recompiled due to an error that generates the following error message:
foo() in ClientClass cannot override foo() in APIClass; overridden method is static
Binary compatibility is be broken as defined in JLS 3/3.14.12
As in the case of rule 2.3, adding a superinterface with a constant field can shadow another entity with the same simple name.