Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public class InlineModelResolver {

// a set to keep track of names generated for inline schemas
private Set<String> uniqueNames = new HashSet<>();
// names that were added through inlineSchemaNameMapping
private Set<String> mappedSchemaNames = new HashSet<>();

// MixIn that suppresses volatile fields when any Schema instance is serialised for structural
// comparison. Registered on Schema.class so it applies recursively to all nested Schema
Expand Down Expand Up @@ -1182,13 +1184,17 @@ private void copyVendorExtensions(Schema source, Schema target) {
private String addSchemas(String name, Schema schema) {
//check inlineSchemaNameMapping
if (inlineSchemaNameMapping.containsKey(name)) {
// use the name chosen by the user as is, even if several inline schemas map to it
name = inlineSchemaNameMapping.get(name);
}

// Recursive flattening can add a nested schema after its parent's name
// was chosen. Re-check here so the parent cannot overwrite that child.
if (openAPI.getComponents().getSchemas().containsKey(name)
if (openAPI.getComponents().getSchemas().containsKey(name)
&& !uniqueNames.contains(name) && !mappedSchemaNames.contains(name)) {
LOGGER.warn("inlineSchemaNameMapping maps an inline schema to `{}`, which is already defined in the spec. The existing `{}` schema is replaced by the inline schema.", name, name);
}
mappedSchemaNames.add(name);
} else if (openAPI.getComponents().getSchemas().containsKey(name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Mapped names now bypass the components.schemas.containsKey(name) check entirely, so a mapped value that collides with an existing spec-defined schema silently overwrites it. addSchemas unconditionally calls openAPI.getComponents().addSchemas(name, schema) (a map put) afterward, so e.g. inlineSchemaNameMapping: {Preview_balance: Money} with a pre-existing components.schemas.Money replaces the original Money definition and rebinds every existing $ref: '#/components/schemas/Money' to the inline schema. Guard the overwrite: only allow the explicit name to win when the existing entry was itself created by an earlier mapping, otherwise fall back to uniqueName(name) (or at least emit a warning before overwriting).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java, line 1187:

<comment>Mapped names now bypass the `components.schemas.containsKey(name)` check entirely, so a mapped value that collides with an existing spec-defined schema silently overwrites it. `addSchemas` unconditionally calls `openAPI.getComponents().addSchemas(name, schema)` (a map put) afterward, so e.g. `inlineSchemaNameMapping: {Preview_balance: Money}` with a pre-existing `components.schemas.Money` replaces the original `Money` definition and rebinds every existing `$ref: '#/components/schemas/Money'` to the inline schema. Guard the overwrite: only allow the explicit name to win when the existing entry was itself created by an earlier mapping, otherwise fall back to `uniqueName(name)` (or at least emit a warning before overwriting).</comment>

<file context>
@@ -1182,13 +1182,12 @@ private void copyVendorExtensions(Schema source, Schema target) {
-        // Recursive flattening can add a nested schema after its parent's name
-        // was chosen. Re-check here so the parent cannot overwrite that child.
-        if (openAPI.getComponents().getSchemas().containsKey(name)
+        } else if (openAPI.getComponents().getSchemas().containsKey(name)
                 || uniqueNames.contains(name)) {
+            // Recursive flattening can add a nested schema after its parent's name
</file context>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the mapped name as is matches 7.25.0, where a mapping onto an existing schema name also replaced it, so I kept that behaviour rather than falling back to uniqueName. In 9867efd the resolver now logs a warning when a mapped name already exists in the spec and wasn't added by an earlier mapping. Several mappings onto the same name (the case from #25179) don't trigger it.

|| uniqueNames.contains(name)) {
// Recursive flattening can add a nested schema after its parent's name
// was chosen. Re-check here so the parent cannot overwrite that child.
name = uniqueName(name);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,25 @@ public void testInlineSchemaNameMapping() {
assertTrue(nothingNew.getProperties().get("arbitrary_request_body_array_property") instanceof ObjectSchema);
}

@Test
public void testInlineSchemaNameMappingManyToOne() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_schema_name_mapping_many_to_one.yaml");
InlineModelResolver resolver = new InlineModelResolver();
Map<String, String> inlineSchemaNames = new HashMap<>();
inlineSchemaNames.put("Preview_balance", "Money");
inlineSchemaNames.put("Preview_interest", "Money");
resolver.setInlineSchemaNameMapping(inlineSchemaNames);
resolver.flatten(openAPI);

Map<String, Schema> schemas = openAPI.getComponents().getSchemas();
assertTrue(schemas.containsKey("Money"));
assertFalse(schemas.containsKey("Money_1"));

Schema preview = schemas.get("Preview");
assertEquals("#/components/schemas/Money", ((Schema) preview.getProperties().get("balance")).get$ref());
assertEquals("#/components/schemas/Money", ((Schema) preview.getProperties().get("interest")).get$ref());
}

@Test
public void testInlineSchemaOptions() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
openapi: 3.0.3
info:
title: inlineSchemaNameMappings many-to-one
version: "1"
paths:
/preview:
get:
responses:
"200":
description: ok
content:
application/json:
schema:
$ref: "#/components/schemas/Preview"
components:
schemas:
Preview:
type: object
properties:
balance:
type: object
description: The balance at the end of the range.
properties:
amount:
type: string
currency:
type: string
interest:
type: object
description: The interest accrued over the range.
properties:
amount:
type: string
currency:
type: string