fix: do not mint a duplicate model for a single-$ref allOf property - #18
fix: do not mint a duplicate model for a single-$ref allOf property#18rmocanu-ionos wants to merge 2 commits into
Conversation
InlineModelResolver.isModelNeeded() treated a property written as
properties:
bootVolume:
allOf:
- $ref: '#/components/schemas/ResourceReference'
description: ...
as needing its own inline model, so the resolver minted a duplicate
<Parent><Property> schema (ServerPropertiesBootVolume) instead of
reusing the referenced one. The sibling keyword is the trigger: a bare
$ref cannot carry a description, so spec authors wrap it in a
single-element allOf, which is the idiomatic OpenAPI 3.0 workaround and
means "this property IS the referenced schema".
The existing loop below dereferences each allOf member via
getReferencedSchema() and reports "model needed" for any object target,
which is correct for a real composition but wrong for the alias case.
Handle the single-$ref case before that loop and recurse on the RAW ref
schema, so the property resolves to the referenced model.
Effect on the IONOS cloudapi-v6 spec, measured A/B against an otherwise
identical run: ServerProperties.bootCdrom and bootVolume resolve to
ResourceReference and maintenanceWindow to ServerMaintenanceWindow,
matching what sdk-go has shipped since v6.3.11. 21 exported symbols
removed, 0 added, 3 dead files gone; purely subtractive. Verified for
go (build + vet), java (mvn compile), node (tsc --noEmit) and python.
Note this is subtractive by construction: it removes generated types
that were duplicates. Before pointing an already-released product at
this build, check that none of the types it drops are types that
product has shipped.
Uses a plain null/isEmpty check rather than StringUtils.isNotEmpty,
which the codegen StringUtils imported by this file does not provide.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Prevents duplicate inline models for properties represented by a single-reference allOf.
Changes:
- Detects single-
$refallOfaliases. - Reuses the referenced schema instead of minting a duplicate model.
Suppressed comments (1)
modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java:244
- This model-resolution regression is not covered by an automated test, although
InlineModelResolverTestextensively testsflatten. Add a property with a description plus a single-$refallOfand assert that flattening reuses the referenced schema without creating<Parent>_<property>; include a combined-composition case so the alias shortcut remains narrowly scoped.
return isModelNeeded(m.getAllOf().get(0), visitedSchemas);
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (isSingleAllOf && m.getAllOf().get(0).get$ref() != null | ||
| && !m.getAllOf().get(0).get$ref().isEmpty()) { |
There was a problem hiding this comment.
Added the regression test (testSingleRefAllOfPropertyReusesReferencedSchema + fixture) — it fails on the parent commit and passes with the fix, 45 tests green.
Skipping the guard: allOf combined with anyOf/oneOf/not occurs nowhere in public/cloud/v6.ga.yaml, public-preview/cloud/v7.ea.yml, or any fixture with a $ref allOf member, so the path is unreachable for this fork. Two notes on the reasoning though — isModelNeeded has no not check at all, and the pre-existing allOf loop already returned before the anyOf/oneOf checks, so the ordering isn't the mechanism, the changed return value is.
Regression test for the isModelNeeded change: a property written as a single-element allOf around a $ref is an alias for the referenced schema, so it must not get a model of its own. Verified to discriminate rather than pass vacuously -- against the parent commit it fails on the assertNull, since the resolver mints ServerProperties_bootVolume there. 45 tests, 0 failures with the fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
InlineModelResolver.isModelNeeded() treated a property written as
as needing its own inline model, so the resolver minted a duplicate schema (ServerPropertiesBootVolume) instead of reusing the referenced one. The sibling keyword is the trigger: a bare $ref cannot carry a description, so spec authors wrap it in a single-element allOf, which is the idiomatic OpenAPI 3.0 workaround and means "this property IS the referenced schema".
The existing loop below dereferences each allOf member via getReferencedSchema() and reports "model needed" for any object target, which is correct for a real composition but wrong for the alias case. Handle the single-$ref case before that loop and recurse on the RAW ref schema, so the property resolves to the referenced model.
Effect on the IONOS cloudapi-v6 spec, measured A/B against an otherwise identical run: ServerProperties.bootCdrom and bootVolume resolve to ResourceReference and maintenanceWindow to ServerMaintenanceWindow, matching what sdk-go has shipped since v6.3.11. 21 exported symbols removed, 0 added, 3 dead files gone; purely subtractive. Verified for go (build + vet), java (mvn compile), node (tsc --noEmit) and python.
Note this is subtractive by construction: it removes generated types that were duplicates. Before pointing an already-released product at this build, check that none of the types it drops are types that product has shipped.
Uses a plain null/isEmpty check rather than StringUtils.isNotEmpty, which the codegen StringUtils imported by this file does not provide.
PR checklist
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*.For Windows users, please run the script in Git BASH.
master(6.3.0) (minor release - breaking changes with fallbacks),7.0.x(breaking changes without fallbacks)