Breaking binary compatibility due to adding private method to an interface compiled inconsistently

Georgiy Rakov georgiy.rakov at oracle.com
Tue Oct 18 14:55:09 UTC 2016


I'd like to emphasize that in this case preexisting binaries supplied to 
JVM during Test.main execution doesn't change and if they don't then, 
according to my understanding, it doesn't matter how the modified B 
class-file was produced.

Thank you,
Georgiy.

On 17.10.2016 21:15, Alex Buckley wrote:
> The key phrase is "with preexisting binaries". Given the initial 
> A.class + B.class + Test.class, you get to make ONE change to ONE 
> compilation unit that you recompile independently but inconsistently. 
> The change you would like to make is adding a private method to B, but 
> you can't make that change because of B's superinterface, so no 
> independent recompilation is possible, and the question of whether the 
> change is binary-incompatible is moot.
>
> Alex
>
> On 10/17/2016 10:26 AM, Georgiy Rakov wrote:
>> Hello Dan,
>>
>> comment [1] specifies following assertion and a note:
>>
>>     Adding an 'abstract', ***'private', or 'static'*** method to an
>>     interface does not break compatibility with preexisting binaries.
>>
>>     [Note: I believe we can make this assertion because "adding a
>>     method" means "adding a method that will compile", presumably?
>>     Private and static methods can introduce errors if a reference like
>>     I.m()V previously resolved to an abstract/default method in a
>>     superinterface, and now resolves to the private/static method in I.
>>     But that new method won't compile if there's a method with a
>>     matching signature in a superinterface of I.]
>>
>> Namely, the note reads:
>>
>>     ... "adding a method" means "adding a method that will compile" ...
>>
>> It's questionable if this is a valid point since spec should take into
>> account that a method added might be resulted from inconsistent
>> compilation. For instance:
>>
>> 1. First we compile sources A.java, B.java, Test.java presented below.
>>
>>     A.java:
>>     interface A {
>>          default void same() {}
>>     }
>>
>>     B.java:
>>     interface B extends A {
>>          //private void same() {}
>>     }
>>
>>     Test.java:
>>     class Test {
>>          public static void main(String[] argv) {
>>               B i = new B(){};
>>               i.same();
>>          }
>>     }
>>
>> 2. Then we compile sources A.java, B.java presented below (toggle
>> commenting 'same' method in A and B):
>>
>>     A.java:
>>     interface A {
>>          //default void same() {}
>>     }
>>
>>     B.java:
>>     interface B extends A {
>>          private void same() {}
>>     }
>>
>>
>> 3. Then we compile source A.java presented below (returning back A class
>> file as it resulted from step 1):
>>
>>     A.java:
>>     interface A {
>>          default void same() {}
>>     }
>>
>> 4. Run Test.main(), this results in a run-time error:
>>
>>     Exception in thread "main" java.lang.IllegalAccessError: tried to
>>     access method B.same()V from class Test
>>
>> So adding a private method seems to cause breaking binary compatibility.
>> The change between binaries resulted from step 1 and step 3 is B class
>> file with a private method added, the rest of the class files are the 
>> same.
>>
>> Should it be considered as a spec issue?
>>
>> [1]
>> https://bugs.openjdk.java.net/browse/JDK-8072872?focusedCommentId=13610992 
>>
>>
>> Thank you,
>> Georgiy.



More information about the compiler-dev mailing list