Skip to content

Commit bb7c33b

Browse files
donaldKejia Liu
andauthored
fix: keep allOf members that have properties alongside a validation keyword (#24551)
A schema carrying `properties` but omitting `type: object`, next to a validation keyword, was classified as "validation without a type" and silently dropped from allOf. Every model inheriting it lost those properties -- no error, no warning, just a smaller model and a broken JSON contract: Parent: minProperties: 2 # validation keyword, no `type: object` properties: alpha: { type: string } beta: { type: string } Child: allOf: [{ $ref: '#/components/schemas/Parent' }] properties: gamma: { type: string } // before: Child has only `gamma` // after: Child has `alpha`, `beta`, `gamma` OpenAPINormalizer.removeUnsupportedSchemasFromAllOf() drops any allOf member for which ModelUtils.isUnsupportedSchema() returns true, and that check was: schema.getTypes() == null && hasValidation(schema) Omitting `type: object` next to `properties` is very common in 3.0 specs, and getTypes() is only populated for 3.1, so in practice any 3.0 schema with a validation keyword and no explicit type was judged unsupported -- including ones that are plainly models. Require that the schema also has no properties (and check getType() as well, so the 3.0 case is recognised at all). A schema with properties is a model, not bare validation. Regenerating all 787 sample configs produces no diff. Co-authored-by: Kejia Liu <kejia@yaocheng.cn>
1 parent b20cbb0 commit bb7c33b

3 files changed

Lines changed: 78 additions & 1 deletion

File tree

‎modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2739,8 +2739,18 @@ public static boolean isUnsupportedSchema(OpenAPI openAPI, Schema schema) {
27392739
// dereference the schema
27402740
schema = ModelUtils.getReferencedSchema(openAPI, schema);
27412741

2742-
if (schema.getTypes() == null && hasValidation(schema)) {
2742+
if (schema.getTypes() == null && schema.getType() == null && hasValidation(schema)
2743+
&& (schema.getProperties() == null || schema.getProperties().isEmpty())) {
27432744
// just validation without type
2745+
//
2746+
// A schema that carries properties is a model, even when it omits `type: object` --
2747+
// which is very common in 3.0 specs, e.g. `minProperties: 2` next to `properties: {...}`.
2748+
// Checking `getTypes() == null && hasValidation(schema)` alone classified those as
2749+
// unsupported, and as an allOf member their properties were then dropped from the
2750+
// composed model without any warning.
2751+
//
2752+
// getTypes() is only populated for 3.1, so getType() has to be checked as well for the
2753+
// 3.0 case to be recognised.
27442754
return true;
27452755
} else if (schema.getIf() != null && schema.getThen() != null) {
27462756
// if, then in 3.1 spec

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,41 @@ public class OpenAPINormalizerTest {
4949
private static final String X_PARENT = "x-parent";
5050
private static final String X_INTERNAL = "x-internal";
5151

52+
@Test
53+
public void testAllOfMemberWithValidationAndPropertiesIsKept() {
54+
// A schema carrying `properties` but omitting `type: object`, next to a validation keyword,
55+
// is a model -- not "validation without a type". It used to be classified as unsupported and
56+
// silently dropped from allOf, so every model inheriting it lost those properties.
57+
OpenAPI openAPI = TestUtils.parseSpec(
58+
"src/test/resources/3_0/allof-member-with-validation-and-properties.yaml");
59+
60+
Schema child = openAPI.getComponents().getSchemas().get("Child");
61+
assertNotNull(child.getAllOf());
62+
assertTrue(refsParent(child), "precondition: Child starts out referencing Parent");
63+
64+
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, new HashMap<>());
65+
openAPINormalizer.normalize();
66+
67+
Schema normalizedChild = openAPI.getComponents().getSchemas().get("Child");
68+
assertNotNull(normalizedChild.getAllOf(),
69+
"the whole allOf was dropped, so Child lost the inherited properties");
70+
assertTrue(refsParent(normalizedChild),
71+
"the allOf member carrying alpha/beta was dropped, so Child lost those properties");
72+
}
73+
74+
private static boolean refsParent(Schema schema) {
75+
if (schema.getAllOf() == null) {
76+
return false;
77+
}
78+
for (Object item : schema.getAllOf()) {
79+
String ref = ((Schema) item).get$ref();
80+
if (ref != null && ref.endsWith("/Parent")) {
81+
return true;
82+
}
83+
}
84+
return false;
85+
}
86+
5287
@Test
5388
public void testOpenAPINormalizerOtherThanObjectWithProperties()
5489
{
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
openapi: 3.0.3
2+
info:
3+
title: allOf member with validation and properties
4+
version: 1.0.0
5+
paths:
6+
/child:
7+
get:
8+
operationId: getChild
9+
responses:
10+
"200":
11+
description: ok
12+
content:
13+
application/json:
14+
schema:
15+
$ref: "#/components/schemas/Child"
16+
components:
17+
schemas:
18+
# `properties` without an explicit `type: object`, next to a validation keyword.
19+
# This is a model, not "validation without a type".
20+
Parent:
21+
minProperties: 2
22+
properties:
23+
alpha:
24+
type: string
25+
beta:
26+
type: string
27+
Child:
28+
allOf:
29+
- $ref: "#/components/schemas/Parent"
30+
properties:
31+
gamma:
32+
type: string

0 commit comments

Comments
 (0)