Skip to content

Commit 554e10d

Browse files
authored
Fix siblings of $ref using allOf in openapi normalizer (#22364)
* fix ref sibiling using allOf in normalizer * update samples
1 parent 6699ecd commit 554e10d

File tree

11 files changed

+109
-55
lines changed

11 files changed

+109
-55
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,11 @@ protected boolean isSelfReference(String name, Schema subSchema) {
696696
* @return Schema
697697
*/
698698
public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
699+
// normalize reference schema
700+
if (StringUtils.isNotEmpty(schema.get$ref())) {
701+
normalizeReferenceSchema(schema);
702+
}
703+
699704
if (skipNormalization(schema, visitedSchemas)) {
700705
return schema;
701706
}
@@ -763,6 +768,30 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
763768
return schema;
764769
}
765770

771+
/**
772+
* Normalize reference schema with allOf to support sibling properties
773+
*
774+
* @param schema Schema
775+
*/
776+
protected void normalizeReferenceSchema(Schema schema) {
777+
if (schema.getTitle() != null || schema.getDescription() != null
778+
|| schema.getNullable() != null || schema.getDefault() != null || schema.getDeprecated() != null
779+
|| schema.getMaximum() != null || schema.getMinimum() != null
780+
|| schema.getExclusiveMaximum() != null || schema.getExclusiveMinimum() != null
781+
|| schema.getMaxItems() != null || schema.getMinItems() != null
782+
|| schema.getMaxProperties() != null || schema.getMinProperties() != null
783+
|| schema.getMaxLength() != null || schema.getMinLength() != null
784+
|| schema.getWriteOnly() != null || schema.getReadOnly() != null
785+
|| schema.getExample() != null || (schema.getExamples() != null && !schema.getExamples().isEmpty())
786+
|| schema.getMultipleOf() != null || schema.getPattern() != null
787+
|| (schema.getExtensions() != null && !schema.getExtensions().isEmpty())
788+
) {
789+
// create allOf with a $ref schema
790+
schema.addAllOfItem(new Schema<>().$ref(schema.get$ref()));
791+
// clear $ref in original schema
792+
schema.set$ref(null);
793+
}
794+
}
766795

767796
/**
768797
* Check if normalization is needed.

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,10 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31SpecForIssue18184() {
910910

911911
Schema schema2 = openAPI.getComponents().getSchemas().get("Item");
912912
assertEquals(((Schema) schema2.getProperties().get("my_enum")).getAnyOf(), null);
913-
assertEquals(((Schema) schema2.getProperties().get("my_enum")).get$ref(), "#/components/schemas/MyEnum");
913+
assertEquals(((Schema) schema2.getProperties().get("my_enum")).getAllOf().size(), 1);
914+
assertEquals(((Schema) schema2.getProperties().get("my_enum")).getNullable(), true);
915+
assertEquals(((Schema) schema2.getProperties().get("my_enum")).get$ref(), null);
916+
assertEquals(((Schema) ((Schema) schema2.getProperties().get("my_enum")).getAllOf().get(0)).get$ref(), "#/components/schemas/MyEnum");
914917
}
915918

916919
@Test
@@ -1104,7 +1107,10 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
11041107
Schema schema18 = openAPI.getComponents().getSchemas().get("OneOfNullAndRef3");
11051108
// original oneOf removed and simplified to just $ref (oneOf sub-schema) instead
11061109
assertEquals(schema18.getOneOf(), null);
1107-
assertEquals(schema18.get$ref(), "#/components/schemas/Parent");
1110+
assertEquals(schema18.get$ref(), null);
1111+
assertEquals(schema18.getNullable(), true);
1112+
assertEquals(((Schema) schema18.getAllOf().get(0)).get$ref(), "#/components/schemas/Parent");
1113+
11081114

11091115
Schema schema20 = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
11101116
assertEquals(((Schema) schema20.getProperties().get("number")).get$ref(), "#/components/schemas/Number");
@@ -1184,6 +1190,24 @@ public void testOpenAPINormalizerProcessingAllOfSchema31Spec() {
11841190
assertEquals(((Schema) schema2.getProperties().get("property2")).getAllOf(), null);
11851191
}
11861192

1193+
@Test
1194+
public void testOpenAPINormalizerNormalizeReferenceSchema() {
1195+
// to test array schema processing in 3.1 spec
1196+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/unsupported_schema_test.yaml");
1197+
1198+
Schema schema = openAPI.getComponents().getSchemas().get("Dummy");
1199+
assertEquals(((Schema) schema.getProperties().get("property3")).get$ref(), "#/components/schemas/RefSchema");
1200+
1201+
Map<String, String> inputRules = Map.of("NORMALIZE_31SPEC", "true");
1202+
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, inputRules);
1203+
openAPINormalizer.normalize();
1204+
1205+
Schema schema2 = openAPI.getComponents().getSchemas().get("Dummy");
1206+
assertEquals(((Schema) schema2.getProperties().get("property3")).getAllOf().size(), 1);
1207+
assertEquals(((Schema) schema2.getProperties().get("property3")).getDescription(), "Override description in $ref schema");
1208+
assertEquals(((Schema) ((Schema) schema2.getProperties().get("property3")).getAllOf().get(0)).get$ref(), "#/components/schemas/RefSchema");
1209+
}
1210+
11871211
@Test
11881212
public void testOpenAPINormalizerComponentsResponses31Spec() {
11891213
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/common-parameters.yaml");

modules/openapi-generator/src/test/resources/3_1/unsupported_schema_test.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ paths:
2424
$ref: "#/components/schemas/Dummy"
2525
components:
2626
schemas:
27+
RefSchema:
28+
description: reference schema
29+
properties:
30+
id:
31+
type: string
2732
Dummy:
2833
type: object
2934
properties:
@@ -61,4 +66,7 @@ components:
6166
enum:
6267
- FIRST
6368
- SECOND
64-
- THIRD
69+
- THIRD
70+
property3:
71+
$ref: "#/components/schemas/RefSchema"
72+
description: Override description in $ref schema

samples/client/others/typescript-node/encode-decode/build/api/defaultApi.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ export class DefaultApi {
334334
/**
335335
*
336336
*/
337-
public async testDecodeArrayOfNullableObjectsGet (options: {headers: {[name: string]: string}} = {headers: {}}) : Promise<{ response: http.IncomingMessage; body: Array<ComplexObject>; }> {
337+
public async testDecodeArrayOfNullableObjectsGet (options: {headers: {[name: string]: string}} = {headers: {}}) : Promise<{ response: http.IncomingMessage; body: Array<ComplexObject | null>; }> {
338338
const localVarPath = this.basePath + '/test/decode/array-of/nullable-objects';
339339
let localVarQueryParameters: any = {};
340340
let localVarHeaderParams: any = (<any>Object).assign({}, this._defaultHeaders);
@@ -376,13 +376,13 @@ export class DefaultApi {
376376
localVarRequestOptions.form = localVarFormParams;
377377
}
378378
}
379-
return new Promise<{ response: http.IncomingMessage; body: Array<ComplexObject>; }>((resolve, reject) => {
379+
return new Promise<{ response: http.IncomingMessage; body: Array<ComplexObject | null>; }>((resolve, reject) => {
380380
localVarRequest(localVarRequestOptions, (error, response, body) => {
381381
if (error) {
382382
reject(error);
383383
} else {
384384
if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) {
385-
body = ObjectSerializer.deserialize(body, "Array<ComplexObject>");
385+
body = ObjectSerializer.deserialize(body, "Array<ComplexObject | null>");
386386
resolve({ response: response, body: body });
387387
} else {
388388
reject(new HttpError(response, body, response.statusCode));
@@ -1187,7 +1187,7 @@ export class DefaultApi {
11871187
*
11881188
* @param complexObject
11891189
*/
1190-
public async testEncodeArrayOfNullableObjectsPost (complexObject: Array<ComplexObject>, options: {headers: {[name: string]: string}} = {headers: {}}) : Promise<{ response: http.IncomingMessage; body?: any; }> {
1190+
public async testEncodeArrayOfNullableObjectsPost (complexObject: Array<ComplexObject | null>, options: {headers: {[name: string]: string}} = {headers: {}}) : Promise<{ response: http.IncomingMessage; body?: any; }> {
11911191
const localVarPath = this.basePath + '/test/encode/array-of/nullable-objects';
11921192
let localVarQueryParameters: any = {};
11931193
let localVarHeaderParams: any = (<any>Object).assign({}, this._defaultHeaders);
@@ -1209,7 +1209,7 @@ export class DefaultApi {
12091209
uri: localVarPath,
12101210
useQuerystring: this._useQuerystring,
12111211
json: true,
1212-
body: ObjectSerializer.serialize(complexObject, "Array<ComplexObject>")
1212+
body: ObjectSerializer.serialize(complexObject, "Array<ComplexObject | null>")
12131213
};
12141214

12151215
let authenticationPromise = Promise.resolve();

samples/client/others/typescript/encode-decode/build/apis/DefaultApi.ts

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/others/typescript/encode-decode/build/docs/DefaultApi.md

Lines changed: 6 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/others/typescript/encode-decode/build/types/ObjectParamAPI.ts

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/others/typescript/encode-decode/build/types/ObservableAPI.ts

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/client/others/typescript/encode-decode/build/types/PromiseAPI.ts

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)