I have the following class:
public abstract Foo { Foo() {} public abstract Foo doSomething(); public static Foo create() { return new SomePrivateSubclassOfFoo(); } }
I want to change it to the following definition:
public abstract Foo<T extends Foo<T>> { Foo() {} public abstract T doSomething(); public static Foo<?> create() { return new SomePrivateSubclassOfFoo(); } }
Is this change binary compatible? Ie, will there be code that is compiled against the old version of the class working with the new version without republishing?
I know that I need to change SomePrivateSubclassOfFoo , this is normal. I also know that this change will cause warnings about raw types when compiling the old client code, this is also normal for me. I just want to make sure that the old client code does not need to be recompiled.
In my opinion, this should be fine, because erasing T is equal to Foo , and thus the doSomething signature in the byte code is the same as before. If I look at the internal caption labels printed by javap -s , I really see it confirmed (although the "non-internal" type javap -s printed without -s are different). I also checked this and it worked for me.
However, the Java API Compliance Checker tells me that the two versions are not binary compatible.
So what is right? Is JLS a guarantee of binary compatibility here, or was I just lucky in my tests? (Why could this happen?)
java generics jls backwards-compatibility
Philip wendler
source share