Repository navigation
API Tools reports compatible method pull-up through non-API superclass as breaking #2499
Description
Activity
- added a commit that references this issue
on Sep 21, 2026 API Tools can incorrectly require a major version bump when a public API method remains available through inheritance from a non-API superclass.
First, while moving a method to a super-class is a source compatible change, I'm in doubt it's a binary-compatible change. IIRC in callers the resolved class defining the method is recoded in the byte code. So moving it up, would break these existing classes and it would make sense to consider it a breaking change. Please check if moving methods up is also binary compatible.
Second, when you say
from a non-API superclass., I again think it's fine to consider it a breaking change if the method is declared in that non-API superclass, since it has effectively vanished from the API and a caller should not (or cannot) access its definition (probably only if it's redeclared in an API class).
But from your example I assume the declaring interface/class is even further up in the hierarchy and API again?Hi Hannes,
Good point. I checked the JLS: it explicitly lists moving a method up the class hierarchy as binary compatible. An already compiled call such as B.m() remains resolvable; the JVM also searches the superclass hierarchy.
I don’t think X being non-exported changes that: client code still refers to B, not X, and B inherits the public method. Of course, changes such as narrowing visibility or switching between instance and static methods must still be treated as breaking, which is why we validate the inherited method before classifying it as a compatible pull-up.
Do you see a specific reason for API Tools to treat this more strictly than JVM binary compatibility?
Cheers
Eike- added a commit that references this issue
on Sep 23, 2026 I checked the compatibility concern in more detail.
The original hierarchy change is binary-compatible:
B.m()remains resolvable through the new superclassX, and both changing the superclass hierarchy without losing former supertypes and moving a method up the hierarchy are covered by JLS 13.4.4 / 13.4.6.While reviewing the broader superclass lookup, I did find one concrete case where the initial fix was too permissive: an exact-signature abstract method in a non-API superclass could have been mistaken for a valid interface implementation.
I tightened
checkSuperInterfaces()accordingly. A matching superclass method is now only accepted if it is public, non-static, concrete, and non-synthetic. A regression test covers the abstract-superclass case.The full API Tools test suite passes: 1,027 tests, no failures or errors.
- added a commit that references this issue
on Sep 26, 2026
API Tools can incorrectly require a major version bump when a public API method remains available through inheritance from a non-API superclass.
Example:
For consumers of
B, the public method remains available:Xitself is not API, but its public method is inherited byB.API Tools currently reports two independent breaking changes for this hierarchy:
EXPANDED_SUPERINTERFACES_SET_BREAKING, because implementation lookup does not consider the non-API superclass;REMOVED | METHOD, because method pull-up detection does not consider the non-API superclass and therefore missesMETHOD_MOVED_UP.Both checks use superclass lists filtered by API visibility although they need to inspect the actual Java superclass hierarchy.
This is particularly problematic because the resulting package-level version error is not accompanied by a filterable culprit problem that could be suppressed to eliminate the version error. As a result, affected refactorings cannot be handled with a targeted API problem filter and effectively force an unnecessary major version increase.
The fix includes non-API superclasses for these implementation lookups.
For
METHOD_MOVED_UP, the matching inherited method is additionally checked for compatibility so the broader lookup does not hide real breaking changes such as:For expanded-superinterface checks, a matching method inherited from a non-API superclass is only considered an implementation if it is public, non-static, concrete, and non-synthetic. This prevents an abstract matching method in an internal superclass from incorrectly suppressing
EXPANDED_SUPERINTERFACES_SET_BREAKING.Regression coverage includes the compatible pull-up scenario, the incompatible moved-method counterexamples, and the abstract internal-superclass counterexample for the expanded-superinterface check.
Validation:
ClassDeltaTests: 163 passedVersionTest: 20 passedClassCompatibilityHierarchyTests: 22 passedorg.eclipse.pde.api.tools.testssuite: 1,027 passed, no failures or errors