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 @@ -1223,7 +1223,15 @@ private void deduplicateComponents() {
String sigKey = schema.getTitle() + "||" + structural;
String canonical = canonicalBySig.get(sigKey);
if (canonical != null) {
duplicateToCanonical.put(name, canonical);
// Only collapse numbered duplicates (e.g. FlowSegment_1) — those are artifacts
// the Swagger Parser / inline resolver produced when it failed to reuse an
// existing component. A schema the user authored with its own distinct,
// non-numbered name is part of the spec's source of truth and must be kept even
// when it is structurally identical to another named schema (see #24177: two
// schemas 'upper1'/'upper2' with the same title, intentionally distinct).
if (name.matches(".*_\\d+$")) {
duplicateToCanonical.put(name, canonical);
}
} else {
canonicalBySig.put(sigKey, name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1487,4 +1487,34 @@ public void deduplicateComponentsRemovesNumberedDuplicateOfTitledSchemaAndRewrit
assertEquals("$ref must be rewritten from Widget_1 to Widget",
"#/components/schemas/Widget", responseSchema.get$ref());
}

@Test
public void deduplicateComponentsKeepsDistinctlyNamedUserSchemas() {
// Regression test for #24177: two component schemas the user authored with distinct,
// non-numbered names (upper1 / upper2) that happen to be structurally identical AND share
// the same title must NOT be merged. deduplicateComponents() only collapses numbered
// duplicates generated by the parser/inline resolver (Foo_1 alongside Foo); user-authored
// named types are the source of truth and must both survive.
OpenAPI openapi = new OpenAPI();
openapi.setComponents(new Components());

Schema upper1 = new ObjectSchema()
.title("foo title identical by purpose")
.description("foo")
.addProperty("foo", new StringSchema());
Schema upper2 = new ObjectSchema()
.title("foo title identical by purpose")
.description("foo")
.addProperty("foo", new StringSchema());

openapi.getComponents().addSchemas("upper1", upper1);
openapi.getComponents().addSchemas("upper2", upper2);

new InlineModelResolver().flatten(openapi);

Map<String, Schema> schemas = openapi.getComponents().getSchemas();
assertNotNull("upper1 must survive", schemas.get("upper1"));
assertNotNull("upper2 must survive — distinctly-named user schemas must not be deduplicated",
schemas.get("upper2"));
}
}
Loading