Skip to content

Commit e361720

Browse files
authored
fix: ExampleGenerator for composed child schemas and array schemas (#18479)
* fix: ExampleGenerator for composed child schemas and array schemas correctly * fix: refactor to remove code duplication * fix: fixes test assertion encoding * fix: adds doc to new method
1 parent 81fab15 commit e361720

16 files changed

Lines changed: 195 additions & 12 deletions

File tree

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

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import io.swagger.v3.core.util.Json;
2121
import io.swagger.v3.oas.models.OpenAPI;
22-
import io.swagger.v3.oas.models.media.ArraySchema;
2322
import io.swagger.v3.oas.models.media.Schema;
2423
import org.apache.commons.lang3.StringUtils;
2524
import org.openapitools.codegen.utils.ModelUtils;
@@ -364,17 +363,7 @@ private Object resolveModelToExample(String name, String mediaType, Schema schem
364363
return schema.getExample();
365364
} else if (ModelUtils.isAllOf(schema) || ModelUtils.isAllOfWithProperties(schema)) {
366365
LOGGER.debug("Resolving allOf model '{}' to example", name);
367-
List<Schema> interfaces = schema.getAllOf();
368-
for (Schema composed : interfaces) {
369-
traverseSchemaProperties(mediaType, composed, processedModels, values);
370-
if (composed.get$ref() != null) {
371-
String ref = ModelUtils.getSimpleRef(composed.get$ref());
372-
Schema resolved = ModelUtils.getSchema(openAPI, ref);
373-
if (resolved != null) {
374-
traverseSchemaProperties(mediaType, resolved, processedModels, values);
375-
}
376-
}
377-
}
366+
resolveAllOfSchemaProperties(mediaType, schema, processedModels, values);
378367
schema.setExample(values);
379368
return schema.getExample();
380369
} else if (ModelUtils.isAnyOf(schema) || ModelUtils.isOneOf(schema)) {
@@ -388,6 +377,8 @@ private Object resolveModelToExample(String name, String mediaType, Schema schem
388377
return null;
389378
}
390379
return resolvePropertyToExample(name, mediaType, found.get(), processedModels);
380+
} else if (ModelUtils.isArraySchema(schema)) {
381+
return resolvePropertyToExample(schema.getName(), mediaType, schema, processedModels);
391382
} else {
392383
// TODO log an error message as the model does not have any properties
393384
return null;
@@ -400,6 +391,29 @@ private void traverseSchemaProperties(String mediaType, Schema schema, Set<Strin
400391
Schema property = (Schema) schema.getProperties().get(propertyName.toString());
401392
values.put(propertyName.toString(), resolvePropertyToExample(propertyName.toString(), mediaType, property, processedModels));
402393
}
394+
} else if (ModelUtils.isAllOf(schema) || ModelUtils.isAllOfWithProperties(schema)) {
395+
resolveAllOfSchemaProperties(mediaType, schema, processedModels, values);
396+
}
397+
}
398+
399+
/**
400+
* Transverse and resolves all property examples for `allOf` composed schemas into `values` map object
401+
* @param mediaType MIME type
402+
* @param schema OAS schema
403+
* @param processedModels Set containing all processed models
404+
* @param values Example value map
405+
*/
406+
private void resolveAllOfSchemaProperties(String mediaType, Schema schema, Set<String> processedModels, Map<String, Object> values) {
407+
List<Schema> interfaces = schema.getAllOf();
408+
for (Schema composed : interfaces) {
409+
traverseSchemaProperties(mediaType, composed, processedModels, values);
410+
if (composed.get$ref() != null) {
411+
String ref = ModelUtils.getSimpleRef(composed.get$ref());
412+
Schema resolved = ModelUtils.getSchema(openAPI, ref);
413+
if (resolved != null) {
414+
traverseSchemaProperties(mediaType, resolved, processedModels, values);
415+
}
416+
}
403417
}
404418
}
405419

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,35 @@ public void generateFromResponseSchemaWithArrayOfPrimitiveTypes() {
152152
assertEquals("200", examples.get(0).get("statusCode"));
153153
}
154154

155+
@Test
156+
public void generateFromResponseSchemaWithArraySchema() {
157+
OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml");
158+
159+
new InlineModelResolver().flatten(openAPI);
160+
161+
ExampleGenerator exampleGenerator = new ExampleGenerator(openAPI.getComponents().getSchemas(), openAPI);
162+
Set<String> mediaTypeKeys = new TreeSet<>();
163+
mediaTypeKeys.add("application/json");
164+
List<Map<String, String>> examples = exampleGenerator.generateFromResponseSchema(
165+
"200",
166+
openAPI
167+
.getPaths()
168+
.get("/generate_from_response_schema_array_reference")
169+
.getGet()
170+
.getResponses()
171+
.get("200")
172+
.getContent()
173+
.get("application/json")
174+
.getSchema(),
175+
mediaTypeKeys
176+
);
177+
178+
assertEquals(1, examples.size());
179+
assertEquals("application/json", examples.get(0).get("contentType"));
180+
assertEquals(String.format(Locale.ROOT, "[ {%n \"example_schema_property\" : \"example schema property value\"%n}, {%n \"example_schema_property\" : \"example schema property value\"%n} ]"), examples.get(0).get("example"));
181+
assertEquals("200", examples.get(0).get("statusCode"));
182+
}
183+
155184
@Test
156185
public void generateFromResponseSchemaWithModel() {
157186
OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml");
@@ -210,6 +239,35 @@ public void generateFromResponseSchemaWithAllOfComposedModel() {
210239
assertEquals("200", examples.get(0).get("statusCode"));
211240
}
212241

242+
@Test
243+
public void generateFromResponseSchemaWithAllOfChildComposedModel() {
244+
OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml");
245+
246+
new InlineModelResolver().flatten(openAPI);
247+
248+
ExampleGenerator exampleGenerator = new ExampleGenerator(openAPI.getComponents().getSchemas(), openAPI);
249+
Set<String> mediaTypeKeys = new TreeSet<>();
250+
mediaTypeKeys.add("application/json");
251+
List<Map<String, String>> examples = exampleGenerator.generateFromResponseSchema(
252+
"200",
253+
openAPI
254+
.getPaths()
255+
.get("/generate_from_response_schema_with_allOf_child_composed_model")
256+
.getGet()
257+
.getResponses()
258+
.get("200")
259+
.getContent()
260+
.get("application/json")
261+
.getSchema(),
262+
mediaTypeKeys
263+
);
264+
265+
assertEquals(1, examples.size());
266+
assertEquals("application/json", examples.get(0).get("contentType"));
267+
assertEquals(String.format(Locale.ROOT, "{%n \"example_schema_property_composed\" : \"example schema property value composed\",%n \"example_schema_property_composed_parent\" : \"example schema property value composed parent\",%n \"example_schema_property\" : \"example schema property value\"%n}"), examples.get(0).get("example"));
268+
assertEquals("200", examples.get(0).get("statusCode"));
269+
}
270+
213271
@Test
214272
public void generateFromResponseSchemaWithOneOfComposedModel() {
215273
OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml");

modules/openapi-generator/src/test/resources/3_0/example_generator_test.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ paths:
6161
items:
6262
type: string
6363
example: primitive types example value
64+
/generate_from_response_schema_array_reference:
65+
get:
66+
operationId: generateFromResponseSchemaArrayReference
67+
responses:
68+
'200':
69+
description: successful operation
70+
content:
71+
application/json:
72+
schema:
73+
$ref: '#/components/schemas/ExampleArraySchema'
6474
/generate_from_response_schema_with_model:
6575
get:
6676
operationId: generateFromResponseSchemaWithModel
@@ -81,6 +91,16 @@ paths:
8191
application/json:
8292
schema:
8393
$ref: '#/components/schemas/ExampleAllOfSchema'
94+
/generate_from_response_schema_with_allOf_child_composed_model:
95+
get:
96+
operationId: generateFromResponseSchemaWithAllOfModel
97+
responses:
98+
'200':
99+
description: successful operation
100+
content:
101+
application/json:
102+
schema:
103+
$ref: '#/components/schemas/ExampleAllOfParentSchema'
84104
/generate_from_response_schema_with_anyOf_composed_model:
85105
get:
86106
operationId: generateFromResponseSchemaWithAnyOfModel
@@ -131,6 +151,15 @@ components:
131151
example_schema_property_composed:
132152
type: string
133153
example: example schema property value composed
154+
ExampleAllOfParentSchema:
155+
type: object
156+
allOf:
157+
- $ref: '#/components/schemas/ExampleAllOfSchema'
158+
- type: object
159+
properties:
160+
example_schema_property_composed_parent:
161+
type: string
162+
example: example schema property value composed parent
134163
ExampleAnyOfSchema:
135164
type: object
136165
anyOf:
@@ -149,3 +178,7 @@ components:
149178
example_schema_property_composed:
150179
type: string
151180
example: example schema property value composed
181+
ExampleArraySchema:
182+
type: array
183+
items:
184+
$ref: '#/components/schemas/ExampleSchema'

samples/client/petstore/csharp/generichost/net8/FormModels/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,10 @@ components:
12471247
type: array
12481248
RolesReportsHash:
12491249
description: Role report Hash
1250+
example:
1251+
role:
1252+
name: name
1253+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
12501254
properties:
12511255
role_uuid:
12521256
format: uuid
@@ -2714,6 +2718,8 @@ components:
27142718
- country
27152719
type: object
27162720
RolesReportsHash_role:
2721+
example:
2722+
name: name
27172723
properties:
27182724
name:
27192725
type: string

samples/client/petstore/csharp/generichost/net8/NullReferenceTypes/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,10 @@ components:
12781278
type: array
12791279
RolesReportsHash:
12801280
description: Role report Hash
1281+
example:
1282+
role:
1283+
name: name
1284+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
12811285
properties:
12821286
role_uuid:
12831287
format: uuid
@@ -2862,6 +2866,8 @@ components:
28622866
- country
28632867
type: object
28642868
RolesReportsHash_role:
2869+
example:
2870+
name: name
28652871
properties:
28662872
name:
28672873
type: string

samples/client/petstore/csharp/generichost/net8/Petstore/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,10 @@ components:
12781278
type: array
12791279
RolesReportsHash:
12801280
description: Role report Hash
1281+
example:
1282+
role:
1283+
name: name
1284+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
12811285
properties:
12821286
role_uuid:
12831287
format: uuid
@@ -2862,6 +2866,8 @@ components:
28622866
- country
28632867
type: object
28642868
RolesReportsHash_role:
2869+
example:
2870+
name: name
28652871
properties:
28662872
name:
28672873
type: string

samples/client/petstore/csharp/generichost/net8/SourceGeneration/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,10 @@ components:
12781278
type: array
12791279
RolesReportsHash:
12801280
description: Role report Hash
1281+
example:
1282+
role:
1283+
name: name
1284+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
12811285
properties:
12821286
role_uuid:
12831287
format: uuid
@@ -2862,6 +2866,8 @@ components:
28622866
- country
28632867
type: object
28642868
RolesReportsHash_role:
2869+
example:
2870+
name: name
28652871
properties:
28662872
name:
28672873
type: string

samples/client/petstore/csharp/generichost/standard2.0/Petstore/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,10 @@ components:
12781278
type: array
12791279
RolesReportsHash:
12801280
description: Role report Hash
1281+
example:
1282+
role:
1283+
name: name
1284+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
12811285
properties:
12821286
role_uuid:
12831287
format: uuid
@@ -2862,6 +2866,8 @@ components:
28622866
- country
28632867
type: object
28642868
RolesReportsHash_role:
2869+
example:
2870+
name: name
28652871
properties:
28662872
name:
28672873
type: string

samples/client/petstore/csharp/httpclient/standard2.0/Petstore/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,10 @@ components:
12781278
type: array
12791279
RolesReportsHash:
12801280
description: Role report Hash
1281+
example:
1282+
role:
1283+
name: name
1284+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
12811285
properties:
12821286
role_uuid:
12831287
format: uuid
@@ -2862,6 +2866,8 @@ components:
28622866
- country
28632867
type: object
28642868
RolesReportsHash_role:
2869+
example:
2870+
name: name
28652871
properties:
28662872
name:
28672873
type: string

samples/client/petstore/csharp/restsharp/net4.7/Petstore/api/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,10 @@ components:
13041304
type: array
13051305
RolesReportsHash:
13061306
description: Role report Hash
1307+
example:
1308+
role:
1309+
name: name
1310+
role_uuid: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
13071311
properties:
13081312
role_uuid:
13091313
format: uuid
@@ -2894,6 +2898,8 @@ components:
28942898
- country
28952899
type: object
28962900
RolesReportsHash_role:
2901+
example:
2902+
name: name
28972903
properties:
28982904
name:
28992905
type: string

0 commit comments

Comments
 (0)