removing a method from an unstable interface breaks compatibility checks for implementing classes.
Consider this interface:
@Unstable
interface Foo {
default void one() {
... do something
}
void two();
}
and an implementing class
class Bar implements Foo {
void two() {
... do something else
}
}
(@Unstable is an annotation that we ignore for japicmp using @Unstable in the exclude config for the maven plugin).
We shipped this code for a while. It turns out that the "One" default method needs to go away. removing it, results in
WARNING: Incompatibility detected: Requires semantic version level MAJOR: JApiMethod [oldMethod=Bar.one(), newMethod=n.a., returnType=JApiReturnType [oldReturnTypeOptional=void, newReturnTypeOptional=void, changeStatus=REMOVED], getCompatibilityChanges()=[JApiCompatibilityChange{type=METHOD_REMOVED}]]
(or similar).
That was surprising. My assumption was, because the "Foo" interface is unstable and the method is not overridden in the implementing class, removing it would be no problem.
Adding the @Unstable annotation temporarily to class Bar is worse, because now the class "disappears" from the japicmp run and I get different errors.
Is this "works as designed"? How do I mark an interface default method in an unstable interface so that I can actually remove it without breaking japicmp?
Consider this interface:
@Unstable interface Foo { default void one() { ... do something }
void two();} and an implementing class
class Bar implements Foo { void two() { ... do something else } } (
@Unstableis an annotation that we ignore for japicmp using@Unstablein the exclude config for the maven plugin).We shipped this code for a while. It turns out that the "One" default method needs to go away. removing it, results in
WARNING: Incompatibility detected: Requires semantic version level MAJOR: JApiMethod [oldMethod=Bar.one(), newMethod=n.a., returnType=JApiReturnType [oldReturnTypeOptional=void, newReturnTypeOptional=void, changeStatus=REMOVED], getCompatibilityChanges()=[JApiCompatibilityChange{type=METHOD_REMOVED}]](or similar).
That was surprising. My assumption was, because the "Foo" interface is unstable and the method is not overridden in the implementing class, removing it would be no problem.
Adding the
@Unstableannotation temporarily toclass Baris worse, because now the class "disappears" from the japicmp run and I get different errors.Is this "works as designed"? How do I mark an interface default method in an unstable interface so that I can actually remove it without breaking japicmp?
Do I understand it right, that you exclude interfaces with the annotation Unstable but not the implementing classes?
If this is what you are doing, I think it works as expected because the class Bar no longer has the method one. So clients of this class will brake when still using one.
Yes. The point is to convey to users that "the interface Foo is still under development" (The annotations are actually called @Alpha and @Beta) and we reserve the right to change things annotated with those. My expectation for japicmp would be that "if something is marked with such an annotation, then a change would result in a message or a warning, not an error".
Basically toning down the strict "that is not compatible" stance.
As japicmp checks for direct annotations, I would have expected that in the case of "implemented methods of an interface", the check would cascade "up the inheritance tree".
Is there somewhere an overview of which annotations are recognized by japicmp?
There is no predefined set of annotations. You can configure what annotation to use:
<parameter>
<includes>
<include>@my.AnnotationToInclude</include>
</includes>
<excludes>
<exclude>@my.AnnotationToExclude</exclude>
</excludes>