Skip to content

Commit c793b37

Browse files
authored
Consider callbacks in unused schemas (OpenAPITools#1232)
1 parent 39a5858 commit c793b37

File tree

3 files changed

+126
-29
lines changed

3 files changed

+126
-29
lines changed

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

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.swagger.v3.oas.models.OpenAPI;
2121
import io.swagger.v3.oas.models.Operation;
2222
import io.swagger.v3.oas.models.PathItem;
23+
import io.swagger.v3.oas.models.callbacks.Callback;
2324
import io.swagger.v3.oas.models.headers.Header;
2425
import io.swagger.v3.oas.models.media.ArraySchema;
2526
import io.swagger.v3.oas.models.media.BinarySchema;
@@ -167,40 +168,56 @@ private static void visitOpenAPI(OpenAPI openAPI, OpenAPISchemaVisitor visitor)
167168

168169
if (paths != null) {
169170
for (PathItem path : paths.values()) {
170-
List<Operation> allOperations = path.readOperations();
171-
if (allOperations != null) {
172-
for (Operation operation : allOperations) {
173-
//Params:
174-
if (operation.getParameters() != null) {
175-
for (Parameter p : operation.getParameters()) {
176-
Parameter parameter = getReferencedParameter(openAPI, p);
177-
if (parameter.getSchema() != null) {
178-
visitSchema(openAPI, parameter.getSchema(), null, visitedSchemas, visitor);
179-
}
180-
}
171+
visitPathItem(path, openAPI, visitor, visitedSchemas);
172+
}
173+
}
174+
}
175+
176+
private static void visitPathItem(PathItem pathItem, OpenAPI openAPI, OpenAPISchemaVisitor visitor, List<String> visitedSchemas) {
177+
List<Operation> allOperations = pathItem.readOperations();
178+
if (allOperations != null) {
179+
for (Operation operation : allOperations) {
180+
//Params:
181+
if (operation.getParameters() != null) {
182+
for (Parameter p : operation.getParameters()) {
183+
Parameter parameter = getReferencedParameter(openAPI, p);
184+
if (parameter.getSchema() != null) {
185+
visitSchema(openAPI, parameter.getSchema(), null, visitedSchemas, visitor);
181186
}
187+
}
188+
}
182189

183-
//RequestBody:
184-
RequestBody requestBody = getReferencedRequestBody(openAPI, operation.getRequestBody());
185-
if (requestBody != null && requestBody.getContent() != null) {
186-
for (Entry<String, MediaType> e : requestBody.getContent().entrySet()) {
190+
//RequestBody:
191+
RequestBody requestBody = getReferencedRequestBody(openAPI, operation.getRequestBody());
192+
if (requestBody != null && requestBody.getContent() != null) {
193+
for (Entry<String, MediaType> e : requestBody.getContent().entrySet()) {
194+
if (e.getValue().getSchema() != null) {
195+
visitSchema(openAPI, e.getValue().getSchema(), e.getKey(), visitedSchemas, visitor);
196+
}
197+
}
198+
}
199+
200+
//Responses:
201+
if (operation.getResponses() != null) {
202+
for (ApiResponse r : operation.getResponses().values()) {
203+
ApiResponse apiResponse = getReferencedApiResponse(openAPI, r);
204+
if (apiResponse != null && apiResponse.getContent() != null) {
205+
for (Entry<String, MediaType> e : apiResponse.getContent().entrySet()) {
187206
if (e.getValue().getSchema() != null) {
188207
visitSchema(openAPI, e.getValue().getSchema(), e.getKey(), visitedSchemas, visitor);
189208
}
190209
}
191210
}
211+
}
212+
}
192213

193-
//Responses:
194-
if (operation.getResponses() != null) {
195-
for (ApiResponse r : operation.getResponses().values()) {
196-
ApiResponse apiResponse = getReferencedApiResponse(openAPI, r);
197-
if (apiResponse != null && apiResponse.getContent() != null) {
198-
for (Entry<String, MediaType> e : apiResponse.getContent().entrySet()) {
199-
if (e.getValue().getSchema() != null) {
200-
visitSchema(openAPI, e.getValue().getSchema(), e.getKey(), visitedSchemas, visitor);
201-
}
202-
}
203-
}
214+
//Callbacks:
215+
if (operation.getCallbacks() != null) {
216+
for (Callback c : operation.getCallbacks().values()) {
217+
Callback callback = getReferencedCallback(openAPI, c);
218+
if (callback != null) {
219+
for (PathItem p : callback.values()) {
220+
visitPathItem(p, openAPI, visitor, visitedSchemas);
204221
}
205222
}
206223
}
@@ -603,6 +620,35 @@ public static Parameter getParameter(OpenAPI openAPI, String name) {
603620
return null;
604621
}
605622

623+
/**
624+
* If a Callback contains a reference to an other Callback with '$ref', returns the referenced Callback if it is found or the actual Callback in the other cases.
625+
*
626+
* @param openAPI specification being checked
627+
* @param callback potentially containing a '$ref'
628+
* @return callback without '$ref'
629+
*/
630+
public static Callback getReferencedCallback(OpenAPI openAPI, Callback callback) {
631+
if (callback != null && StringUtils.isNotEmpty(callback.get$ref())) {
632+
String name = getSimpleRef(callback.get$ref());
633+
Callback referencedCallback = getCallback(openAPI, name);
634+
if (referencedCallback != null) {
635+
return referencedCallback;
636+
}
637+
}
638+
return callback;
639+
}
640+
641+
public static Callback getCallback(OpenAPI openAPI, String name) {
642+
if (name == null) {
643+
return null;
644+
}
645+
646+
if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getCallbacks() != null) {
647+
return openAPI.getComponents().getCallbacks().get(name);
648+
}
649+
return null;
650+
}
651+
606652
/**
607653
* Return the first defined Schema for a RequestBody
608654
*

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919

2020
import io.swagger.parser.OpenAPIParser;
2121
import io.swagger.v3.oas.models.OpenAPI;
22-
import io.swagger.v3.oas.models.media.*;
22+
import io.swagger.v3.oas.models.media.ComposedSchema;
23+
import io.swagger.v3.oas.models.media.IntegerSchema;
24+
import io.swagger.v3.oas.models.media.ObjectSchema;
25+
import io.swagger.v3.oas.models.media.Schema;
26+
import io.swagger.v3.oas.models.media.StringSchema;
2327
import io.swagger.v3.oas.models.parameters.Parameter;
2428
import io.swagger.v3.oas.models.parameters.RequestBody;
2529
import io.swagger.v3.oas.models.responses.ApiResponse;
@@ -40,7 +44,7 @@ public class ModelUtilsTest {
4044
public void testGetAllUsedSchemas() {
4145
final OpenAPI openAPI = new OpenAPIParser().readLocation("src/test/resources/3_0/unusedSchemas.yaml", null, new ParseOptions()).getOpenAPI();
4246
List<String> allUsedSchemas = ModelUtils.getAllUsedSchemas(openAPI);
43-
Assert.assertEquals(allUsedSchemas.size(), 28);
47+
Assert.assertEquals(allUsedSchemas.size(), 30);
4448

4549
Assert.assertTrue(allUsedSchemas.contains("SomeObjShared"), "contains 'SomeObjShared'");
4650
Assert.assertTrue(allUsedSchemas.contains("SomeObj1"), "contains 'UnusedObj1'");
@@ -70,6 +74,8 @@ public void testGetAllUsedSchemas() {
7074
Assert.assertTrue(allUsedSchemas.contains("Obj19ByType"), "contains 'Obj19ByType'");
7175
Assert.assertTrue(allUsedSchemas.contains("SomeObj20"), "contains 'SomeObj20'");
7276
Assert.assertTrue(allUsedSchemas.contains("OtherObj20"), "contains 'OtherObj20'");
77+
Assert.assertTrue(allUsedSchemas.contains("PingDataInput21"), "contains 'PingDataInput21'");
78+
Assert.assertTrue(allUsedSchemas.contains("PingDataOutput21"), "contains 'PingDataOutput21'");
7379
}
7480

7581
@Test

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,36 @@ paths:
233233
text/plain:
234234
schema:
235235
$ref: '#/components/schemas/SomeObj20'
236+
/some/p21:
237+
post:
238+
operationId: op21
239+
parameters:
240+
- name: callbackUrl
241+
in: query
242+
required: true
243+
schema:
244+
type: string
245+
format: uri
246+
example: https://some-server.com
247+
responses:
248+
'201':
249+
description: OK
250+
callbacks:
251+
onPing:
252+
'{$request.query.callbackUrl}/ping':
253+
post:
254+
requestBody:
255+
content:
256+
application/json:
257+
schema:
258+
$ref: '#/components/schemas/PingDataInput21'
259+
responses:
260+
'200':
261+
description: Ok
262+
content:
263+
application/json:
264+
schema:
265+
$ref: '#/components/schemas/PingDataOutput21'
236266
components:
237267
schemas:
238268
UnusedObj1:
@@ -463,6 +493,20 @@ components:
463493
OtherObj20:
464494
type: string
465495
enum: [A, B, C]
496+
PingDataInput21:
497+
type: object
498+
properties:
499+
id:
500+
type: integer
501+
data:
502+
type: String
503+
PingDataOutput21:
504+
type: object
505+
properties:
506+
id:
507+
type: integer
508+
reply:
509+
type: String
466510
SomeObjShared:
467511
type: object
468512
properties:
@@ -515,4 +559,5 @@ components:
515559
name: id
516560
in: query
517561
schema:
518-
$ref: '#/components/schemas/SomeObj11'
562+
$ref: '#/components/schemas/SomeObj11'
563+

0 commit comments

Comments
 (0)