fix(InlineModelResolver): prevent numbered duplicate models from multi-file OAS 3.1 specs#23856
Open
Shaun-3adesign wants to merge 2 commits into
Conversation
Member
|
thanks for the PR can you please review the change in samples (https://github.com/OpenAPITools/openapi-generator/actions/runs/26329184806/job/77535132168?pr=23856) to see if these are expected? |
…i-file OAS 3.1 specs
When a multi-file OpenAPI 3.1 spec uses external $ref schemas (e.g. JSON
Schema files), the swagger-parser resolves them into shared, mutable Java
Schema objects. Between processing passes the parser mutates these shared
objects in several ways that cause matchGenerated() to produce false misses,
which in turn cause numbered duplicate component schemas to be emitted:
* Strips 'type' annotations (e.g. type:"string") from property sub-schemas
* Strips 'description' text from shared property sub-schemas
* Leaves 'example' set on one $ref usage but absent on another (OAS 3.1
allows 'example' as a $ref sibling)
* Stores an explicit 'default: null' in YAML as a Jackson NullNode (a
non-null Java object serialised as '"default":null'), while a property
with no 'default' keyword at all produces a Java null that the NON_NULL
mapper omits — two representations of "no default" that compared unequal
These mutations caused matchGenerated() to fail its structural comparison,
creating e.g. Flow_Segment_1 alongside Flow_Segment for the TAMS-BBC spec.
Changes:
1. IgnoreVolatileFieldsMixIn — extends @JsonIgnoreProperties to strip
'description', 'type', and 'example' at every level of the schema graph
when computing the structural signature.
2. computeStructuralSignature() — replaces direct structuralMapper calls.
After mixin-based serialisation it parses the JSON tree and removes any
"default":null (NullNode) entries before returning the key, making an
explicit null default compare equal to an absent default while preserving
real non-null defaults (e.g. default:"available").
3. Pre-populate generatedSignature / generatedStructuralSignature with
titled schemas already in components/schemas before flattening begins, so
that subsequent inline schemas matching existing ones reuse the existing
name rather than receiving a numbered suffix. Only titled schemas are
pre-populated: a schema identified only by its YAML key in
components/schemas has no inherent identity — two anonymous schemas that
share the same properties may be intentionally distinct.
4. deduplicateComponents() — post-flatten safety-net pass that scans
components/schemas for titled schemas whose structural signatures match,
removes the numbered duplicate (e.g. Flow_Segment_1), and rewrites every
$ref throughout paths, webhooks, and component schemas to point to the
canonical name.
5. Tests — two new regression tests in InlineModelResolverTest plus a set
of multi-file YAML fixtures in src/test/resources/3_0/inline-model-
resolver-dedup/ that reproduce the parser-mutation scenario:
* resolveInlineModelDeduplicatesWhenParserMutatesPropertyTypes — verifies
the structural-hash fallback fires when the parser strips 'type' from
string properties of a shared Schema object
* deduplicateComponentsRemovesNumberedDuplicateOfTitledSchemaAndRewritesRefs
— verifies the post-flatten dedup removes the numbered copy and
rewrites all $refs in path responses
… deduplication fixes Regenerated all samples via bin/generate-samples.sh (maven:3.9-eclipse-temurin-11, matching CI JDK version) to reflect the corrected InlineModelResolver behaviour introduced in the two preceding commits. Affected generators and the root cause for each change: csharp-generichost (FormModels, net4.7/4.8/8/9/10) TestEnumParametersEnumHeaderStringParameter removed; enum_header_string and enum_query_string parameters now typed as TestEnumParametersRequestEnumFormString. Reason: the header-string and query-string inline enums are structurally identical to the form-string enum; the structural deduplication map (ignoring description fields) now correctly merges them instead of generating a numbered duplicate. python / python-aiohttp / python-httpx / python-lazyImports / python-pydantic-v1 / python-pydantic-v1-aiohttp UploadFileWithAdditionalPropertiesRequestObject removed; the upload_file_with_ additional_properties endpoint's object parameter is now typed as TestObjectForMultipartRequestsRequestMarker. Reason: same structural-deduplication fix — the inline request schema is structurally identical to the pre-existing TestObjectForMultipartRequestsRequestMarker component and is now correctly reused rather than generating a new model class. php-laravel FakeApiInterface / FakeController updated to reflect the merged type names for both enum and upload-object parameters. rust-server / rust-server-deprecated (petstore-with-fake-endpoints-models-for-testing) TestEnumParametersEnumHeaderStringParameter model and all usages replaced with TestEnumParametersRequestEnumFormString across models.rs, cli.rs, client/mod.rs, server/mod.rs, and example files. openapi.yaml inlined schemas updated accordingly. No functional change — the generated clients/servers remain equivalent; only the model class names for previously-duplicate anonymous schemas have been normalised.
ff3cfc3 to
1214fd1
Compare
Author
Should be good now |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix #23854
Problem
Multi-file OAS 3.1 specs produce numbered duplicate models (e.g.
DeletionRequest1,FlowSegmentPost1,ContainerMapping1) due to threerelated bugs in
InlineModelResolver:components/schemasentries were not seeded into thededuplication map before flattening, so identical inline schemas were
re-registered under numbered names.
$ref+ siblingdescription(per JSON Schema 2020-12);the parser produces a Schema with an overridden description, making the
content hash differ from the canonical registered schema.
usages of the same external file (e.g.
uuid.json). Properties thatcarry a sibling description overwrite the shared object's
descriptionin-place, so two Schema instances from the same source file end up with
entirely different serialised content depending on processing order.
Fix
generatedSignaturefromcomponents/schemasat the start offlatten().generatedStructuralSignature) keyed ona description-free serialisation. Uses a Jackson
ObjectMapperwith a@JsonIgnoreProperties({"description"})MixIn registered onSchema.class,which suppresses
descriptionrecursively across the entire schema graph.The exact-hash path is tried first to avoid false-positive merges.
Tests
Four regression tests added to
InlineModelResolverTest, plus a set ofmulti-file YAML fixtures under
src/test/resources/3_0/inline-model-resolver-dedup/that model the structure of the spec that triggered the bugs.
Summary by cubic
Prevents
InlineModelResolverfrom emitting numbered duplicate models when flattening multi-file OpenAPI 3.1 specs, even when the parser mutates shared schemas. Keeps component names canonical and rewrites$refs to the canonical schema.components/schemasbefore flattening; avoids hijacking untitled inline schemas.description,type, andexample, and treatsdefault: nullas absent; used as a fallback after the exact hash.$refs across paths, webhooks, and components.Written for commit 1214fd1. Summary will update on new commits. Review in cubic