Follow-up to #887 / #916.
#916 fixed the ClassCastException for allOf-wrapped array → direct type: array. The opposite direction does not throw, but reports a breaking change between two equivalent specs.
Reproduction
Using the fixtures added in #916, with the arguments swapped:
OpenApiCompare.fromLocations("issue-887-2.yaml", "issue-887-1.yaml");
Output:
* Changed property `valuations` (array -> array)
#### Result
API changes broke backward compatibility
Left side:
valuations:
type: array
items:
$ref: '#/components/schemas/Valuation'
Right side:
valuations:
allOf:
- $ref: '#/components/schemas/Valuations' # Valuations is `type: array`
Both describe the same array, so the expected result is no change / compatible — which is what the forward direction already returns after #916.
Cause
SchemaDiff.computeDiffForReal selects the diff-result implementation from the right-hand schema only:
SchemaDiffResult result = SchemaDiff.getSchemaDiffResult(right.getClass(), openApiDiff);
resolveComposedSchema merges allOf members into the parent but leaves the instance as a ComposedSchema, so with the allOf spec on the right, ComposedSchemaDiffResult is selected. Its else branch fires because left is an ArraySchema rather than a ComposedSchema:
} else {
return openApiDiff.getSchemaDiff().getTypeChangedSchema(left, right, context);
}
That reports a type change even though left.getType() and right.getType() are both array — computeDiffForReal already verified they match before dispatching.
Suggested fix
In ComposedSchemaDiffResult.diff, when left is not a ComposedSchema, fall through to super.diff(...) instead of declaring a type change — the type/format equality check upstream has already passed at that point. The oneOf/discriminator handling stays behind the existing instanceof guard.
More generally, the dispatch being driven solely by right.getClass() makes composed-vs-plain comparisons asymmetric; worth considering whether the result class should be chosen from both sides.
Note
Issue887Test.testDirectArrayToAllOfArrayDoesNotThrow covers this direction but asserts only that no exception is thrown, so it passes against the current wrong output. It should become assertOpenApiAreEquals(DIRECT_ARRAY, ALLOF_ARRAY) once this is fixed.
Follow-up to #887 / #916.
#916 fixed the
ClassCastExceptionforallOf-wrapped array → directtype: array. The opposite direction does not throw, but reports a breaking change between two equivalent specs.Reproduction
Using the fixtures added in #916, with the arguments swapped:
Output:
Left side:
Right side:
Both describe the same array, so the expected result is no change / compatible — which is what the forward direction already returns after #916.
Cause
SchemaDiff.computeDiffForRealselects the diff-result implementation from the right-hand schema only:resolveComposedSchemamergesallOfmembers into the parent but leaves the instance as aComposedSchema, so with theallOfspec on the right,ComposedSchemaDiffResultis selected. Itselsebranch fires becauseleftis anArraySchemarather than aComposedSchema:That reports a type change even though
left.getType()andright.getType()are botharray—computeDiffForRealalready verified they match before dispatching.Suggested fix
In
ComposedSchemaDiffResult.diff, whenleftis not aComposedSchema, fall through tosuper.diff(...)instead of declaring a type change — the type/format equality check upstream has already passed at that point. TheoneOf/discriminator handling stays behind the existinginstanceofguard.More generally, the dispatch being driven solely by
right.getClass()makes composed-vs-plain comparisons asymmetric; worth considering whether the result class should be chosen from both sides.Note
Issue887Test.testDirectArrayToAllOfArrayDoesNotThrowcovers this direction but asserts only that no exception is thrown, so it passes against the current wrong output. It should becomeassertOpenApiAreEquals(DIRECT_ARRAY, ALLOF_ARRAY)once this is fixed.