Breaking binary compatibility due to adding private method to an interface compiled inconsistently
Alex Buckley
alex.buckley at oracle.com
Mon Oct 17 18:15:06 UTC 2016
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