Skip to content

Commit 84b3443

Browse files
committed
fixes for recursion issue in resolveFully
1 parent eab9a28 commit 84b3443

File tree

3 files changed

+114
-21
lines changed

3 files changed

+114
-21
lines changed

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import io.swagger.v3.parser.models.RefFormat;
2020
import org.slf4j.Logger;
2121
import org.slf4j.LoggerFactory;
22-
2322
import java.util.ArrayList;
2423
import java.util.HashMap;
2524
import java.util.HashSet;
@@ -38,6 +37,8 @@ public class ResolverFully {
3837

3938
private boolean aggregateCombinators;
4039

40+
41+
4142
public ResolverFully() {
4243
this(true);
4344
}
@@ -53,6 +54,7 @@ public ResolverFully(boolean aggregateCombinators) {
5354
private Map<String, RequestBody> requestBodies;
5455
private Map<String, Header> headers;
5556
private Map<String, Link> links;
57+
private Map<String, Schema> resolvedProperties = new HashMap<>();
5658

5759
public void resolveFully(OpenAPI openAPI) {
5860
if (openAPI.getComponents() != null && openAPI.getComponents().getRequestBodies() != null) {
@@ -259,30 +261,43 @@ public Parameter resolveParameter(Parameter parameter){
259261

260262
public Schema resolveSchema(Schema schema) {
261263
if(schema.get$ref() != null) {
264+
262265
String ref= schema.get$ref();
263266
ref = ref.substring(ref.lastIndexOf("/") + 1);
264267
Schema resolved = schemas.get(ref);
265-
if(resolved == null) {
266-
LOGGER.error("unresolved model " + ref);
267-
return schema;
268-
}
269-
if(this.resolvedModels.containsKey(ref)) {
270-
LOGGER.debug("avoiding infinite loop");
271-
return this.resolvedModels.get(ref);
272-
}
273-
this.resolvedModels.put(ref, schema);
274268

275-
Schema model = resolveSchema(resolved);
269+
if (resolved != null) {
276270

277-
// if we make it without a resolution loop, we can update the reference
278-
this.resolvedModels.put(ref, model);
279-
return model;
271+
if (this.resolvedModels.containsKey(ref)) {
272+
LOGGER.debug("avoiding infinite loop");
273+
return resolvedModels.get(ref);
274+
}
275+
resolvedModels.put(ref, schema);
276+
Schema model = resolveSchema(resolved);
277+
278+
// if we make it without a resolution loop, we can update the reference
279+
resolvedModels.put(ref, model);
280+
281+
282+
return model;
283+
284+
}else {
285+
return schema;
286+
}
280287
}
281288

282289
if(schema instanceof ArraySchema) {
283290
ArraySchema arrayModel = (ArraySchema) schema;
284291
if(arrayModel.getItems().get$ref() != null) {
285-
arrayModel.setItems(resolveSchema(arrayModel.getItems()));
292+
String ref= arrayModel.getItems().get$ref();
293+
ref = ref.substring(ref.lastIndexOf("/") + 1);
294+
if (resolvedModels.get(ref) == null) {
295+
arrayModel.setItems(resolveSchema(arrayModel.getItems()));
296+
}else{
297+
arrayModel.setItems(resolvedModels.get(ref));
298+
//validar que tan profundo estoy en la recursion para cortar con la asignacion de propiedades.
299+
arrayModel.getItems().set$ref(arrayModel.getItems().get$ref());
300+
}
286301
} else {
287302
arrayModel.setItems(arrayModel.getItems());
288303
}
@@ -331,7 +346,14 @@ public Schema resolveSchema(Schema schema) {
331346
if (resolved.getProperties() != null) {
332347
for (String key : properties.keySet()) {
333348
Schema prop = (Schema) resolved.getProperties().get(key);
334-
model.addProperties(key, resolveSchema(prop));
349+
if(resolvedProperties.get(key) == null && resolvedProperties.get(key) != prop) {
350+
LOGGER.debug("avoiding infinite loop");
351+
Schema resolvedProp = resolveSchema(prop);
352+
model.addProperties(key,resolvedProp );
353+
resolvedProperties.put(key, resolvedProp);
354+
}else {
355+
model.addProperties(key,resolvedProperties.get(key));
356+
}
335357
}
336358
if (resolved.getRequired() != null) {
337359
for (int i = 0; i < resolved.getRequired().size(); i++) {
@@ -372,7 +394,14 @@ public Schema resolveSchema(Schema schema) {
372394
if (resolved.getProperties() != null) {
373395
for (String key : properties.keySet()) {
374396
Schema prop = (Schema) resolved.getProperties().get(key);
375-
model.addProperties(key, resolveSchema(prop));
397+
if(resolvedProperties.get(key) == null && resolvedProperties.get(key) != prop) {
398+
LOGGER.debug("avoiding infinite loop");
399+
Schema resolvedProp = resolveSchema(prop);
400+
model.addProperties(key,resolvedProp );
401+
resolvedProperties.put(key, resolvedProp);
402+
}else {
403+
model.addProperties(key,resolvedProperties.get(key));
404+
}
376405
}
377406
if (resolved.getRequired() != null) {
378407
for (int i = 0; i < resolved.getRequired().size(); i++) {
@@ -414,7 +443,14 @@ public Schema resolveSchema(Schema schema) {
414443
if (resolved.getProperties() != null) {
415444
for (String key : properties.keySet()) {
416445
Schema prop = (Schema) resolved.getProperties().get(key);
417-
model.addProperties(key, resolveSchema(prop));
446+
if(resolvedProperties.get(key) == null && resolvedProperties.get(key) != prop) {
447+
LOGGER.debug("avoiding infinite loop");
448+
Schema resolvedProp = resolveSchema(prop);
449+
model.addProperties(key,resolvedProp );
450+
resolvedProperties.put(key, resolvedProp);
451+
}else {
452+
model.addProperties(key,resolvedProperties.get(key));
453+
}
418454
}
419455
if (resolved.getRequired() != null) {
420456
for (int i = 0; i < resolved.getRequired().size(); i++) {
@@ -463,8 +499,15 @@ public Schema resolveSchema(Schema schema) {
463499
Map<String, Schema> properties = model.getProperties();
464500
for (String propertyName : properties.keySet()) {
465501
Schema property = (Schema) model.getProperties().get(propertyName);
466-
Schema resolved = resolveSchema(property);
467-
updated.put(propertyName, resolved);
502+
if(resolvedProperties.get(propertyName) == null && resolvedProperties.get(propertyName) != property) {
503+
LOGGER.debug("avoiding infinite loop");
504+
Schema resolved = resolveSchema(property);
505+
updated.put(propertyName, resolved);
506+
resolvedProperties.put(propertyName, resolved);
507+
}else {
508+
updated.put(propertyName, resolvedProperties.get(propertyName));
509+
510+
}
468511
}
469512

470513
for (String key : updated.keySet()) {

modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIResolverTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import static org.testng.Assert.assertNotNull;
7070
import static org.testng.Assert.assertNull;
7171
import static org.testng.Assert.assertTrue;
72+
import static org.testng.FileAssert.fail;
7273

7374

7475
public class OpenAPIResolverTest {
@@ -432,7 +433,7 @@ public void testSelfReferenceResolution(@Injectable final List<AuthorizationValu
432433
OpenAPI openAPI = new OpenAPIV3Parser().readContents(yaml,auths,options).getOpenAPI();
433434
ResolverFully resolverUtil = new ResolverFully();
434435
resolverUtil.resolveFully(openAPI);
435-
//System.out.println(openAPI.getPaths().get("/selfRefB").getGet().getRequestBody().getContent().get("application/json"));
436+
436437

437438
RequestBody body = openAPI.getPaths().get("/selfRefB").getGet().getRequestBody();
438439
Schema schema = body.getContent().get("application/json").getSchema();
@@ -595,6 +596,7 @@ public void resolveAllOfWithoutAggregatingParameters(@Injectable final List<Auth
595596
assertTrue(allOf.getAllOf().get(0).getProperties().containsKey("street"));
596597
assertTrue(allOf.getAllOf().get(1).getProperties().containsKey("gps"));
597598

599+
598600
// Testing path item
599601
ComposedSchema schema = (ComposedSchema) openAPI.getPaths().get("/withInvalidComposedModel").getPost().getRequestBody().getContent().get("application/json").getSchema();
600602

@@ -1134,6 +1136,21 @@ public void testUpdateInternalReferencesOfExternalFiles() {
11341136
assertEquals(((Schema) coreSchema.getProperties().get("inner")).get$ref(), "#/components/schemas/innerCore");
11351137
}
11361138

1139+
@Test
1140+
public void recursiveResolving() {
1141+
ParseOptions parseOptions = new ParseOptions();
1142+
parseOptions.setResolveFully(true);
1143+
OpenAPI openAPI = new OpenAPIV3Parser().read("recursive.yaml", null, parseOptions);
1144+
Assert.assertNotNull(openAPI.getPaths().get("/myPath").getGet().getResponses().get("200").getContent().get("application/json").getSchema().getProperties().get("myProp"));
1145+
try {
1146+
Json.mapper().writeValueAsString(openAPI);
1147+
}
1148+
catch (Exception e) {
1149+
fail("Recursive loop found");
1150+
}
1151+
1152+
}
1153+
11371154
public String replacePort(String url){
11381155
String pathFile = url.replace("${dynamicPort}", String.valueOf(this.serverPort));
11391156
return pathFile;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
openapi: 3.0.0
2+
info:
3+
version: "0.0.2"
4+
paths:
5+
/myPath:
6+
get:
7+
responses:
8+
"200":
9+
description: Success
10+
content:
11+
application/json:
12+
schema:
13+
$ref: "#/components/schemas/Outer"
14+
application/xml:
15+
schema:
16+
$ref: "#/components/schemas/Test"
17+
components:
18+
schemas:
19+
Outer:
20+
allOf:
21+
- $ref: "#/components/schemas/Inner"
22+
Inner:
23+
properties:
24+
myProp:
25+
type: array
26+
items:
27+
$ref: "#/components/schemas/Inner"
28+
Test:
29+
properties:
30+
myProp:
31+
type: array
32+
items:
33+
$ref: "#/components/schemas/Inner"

0 commit comments

Comments
 (0)