Commit 170778a
authored
fix(InlineModelResolver): prevent numbered duplicate models from multi-file OAS 3.1 specs (#23856)
* fix(InlineModelResolver): prevent numbered duplicate models from multi-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
* chore(samples): regenerate affected samples after InlineModelResolver 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.
* fix(samples): resolve CI failures caused by incomplete sample regeneration after InlineModelResolver deduplication
The previous sample regeneration (1214fd1) after the InlineModelResolver
deduplication fix left two sets of samples in an inconsistent state:
C# GenericHost FormModels (net8, net9, net10, net4.7, net4.8):
- TestEnumParametersEnumHeaderStringParameter was correctly identified as
a structural duplicate of TestEnumParametersRequestEnumFormString and
deduplicated, but the model files (.cs, .md, test .cs) were not deleted
from the committed samples. The API implementation was updated to use
TestEnumParametersRequestEnumFormString, but FakeApiTests.cs still
referenced the deleted type, causing CS1503 compile errors.
- Fix: delete the three orphaned TestEnumParametersEnumHeaderStringParameter
files per variant and update FakeApiTests.cs to use
TestEnumParametersRequestEnumFormString for enumHeaderString and
enumQueryString parameters.
Python petstore samples (python, python-aiohttp, python-httpx,
python-lazyImports, python-pydantic-v1, python-pydantic-v1-aiohttp):
- UploadFileWithAdditionalPropertiesRequestObject was correctly deduplicated
to TestObjectForMultipartRequestsRequestMarker (structurally identical:
both have name: Optional[str] with additional properties). The generated
API method upload_file_with_additional_properties now uses
TestObjectForMultipartRequestsRequestMarker as the object parameter type,
but the hand-written test_rest.py in each variant still instantiated the
old UploadFileWithAdditionalPropertiesRequestObject, causing AttributeError
at runtime.
- Fix: update test_rest.py in all six variants to use
TestObjectForMultipartRequestsRequestMarker instead.
All fixes verified locally via Docker (Python 3.12, poetry run pytest).1 parent 17a4d96 commit 170778a
125 files changed
Lines changed: 824 additions & 1828 deletions
File tree
- modules/openapi-generator/src
- main/java/org/openapitools/codegen
- test
- java/org/openapitools/codegen
- resources/3_0/inline-model-resolver-dedup
- samples
- client/petstore/csharp/generichost
- net10/FormModels
- .openapi-generator
- api
- docs
- apis
- models
- src
- Org.OpenAPITools.Test
- Api
- Model
- Org.OpenAPITools
- Api
- Client
- Model
- net4.7/FormModels
- .openapi-generator
- api
- docs
- apis
- models
- src
- Org.OpenAPITools.Test
- Api
- Model
- Org.OpenAPITools
- Api
- Client
- Model
- net4.8/FormModels
- .openapi-generator
- api
- docs
- apis
- models
- src
- Org.OpenAPITools.Test
- Api
- Model
- Org.OpenAPITools
- Api
- Client
- Model
- net8/FormModels
- .openapi-generator
- api
- docs
- apis
- models
- src
- Org.OpenAPITools.Test
- Api
- Model
- Org.OpenAPITools
- Api
- Client
- Model
- net9/FormModels
- .openapi-generator
- api
- docs
- apis
- models
- src
- Org.OpenAPITools.Test
- Api
- Model
- Org.OpenAPITools
- Api
- Client
- Model
- openapi3/client/petstore
- python-aiohttp
- .openapi-generator
- docs
- petstore_api
- api
- models
- tests
- python-httpx
- .openapi-generator
- docs
- petstore_api
- api
- models
- tests
- python-lazyImports
- .openapi-generator
- docs
- petstore_api
- api
- models
- tests
- python-pydantic-v1-aiohttp
- .openapi-generator
- docs
- petstore_api
- api
- models
- tests
- python-pydantic-v1
- .openapi-generator
- docs
- petstore_api
- api
- models
- tests
- python
- .openapi-generator
- docs
- petstore_api
- api
- models
- tests
- server/petstore
- php-laravel
- .openapi-generator
- Api
- Http/Controllers
- rust-server-deprecated/output/petstore-with-fake-endpoints-models-for-testing
- .openapi-generator
- api
- bin
- examples
- client
- server
- src
- client
- server
- rust-server/output/petstore-with-fake-endpoints-models-for-testing
- .openapi-generator
- api
- bin
- examples
- client
- server
- src
- client
- server
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 287 additions & 2 deletions
Large diffs are not rendered by default.
Lines changed: 227 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
175 | 176 | | |
176 | 177 | | |
177 | 178 | | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
178 | 298 | | |
179 | 299 | | |
180 | 300 | | |
| |||
1205 | 1325 | | |
1206 | 1326 | | |
1207 | 1327 | | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
| 1408 | + | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
1208 | 1435 | | |
Lines changed: 6 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
Lines changed: 8 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
modules/openapi-generator/src/test/resources/3_0/inline-model-resolver-dedup/deletion-request.yaml
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
Lines changed: 8 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
Lines changed: 13 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
Lines changed: 8 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
Lines changed: 62 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
0 commit comments