Skip to content

Commit ec23f8a

Browse files
authored
Merge pull request #1705 from swagger-api/issue1643
Fix and test for issue 1643 - Parser does not validate an undefined ref property
2 parents e29a4f4 + 6be7be5 commit ec23f8a

File tree

3 files changed

+120
-2
lines changed

3 files changed

+120
-2
lines changed

modules/swagger-parser-core/src/main/java/io/swagger/v3/parser/core/models/ParseOptions.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class ParseOptions {
1010
private boolean skipMatches;
1111
private boolean allowEmptyStrings = true;
1212
private boolean validateExternalRefs = false;
13+
private boolean validateInternalRefs = false;
1314
private boolean legacyYamlDeserialization = false;
1415

1516
public boolean isResolve() {
@@ -89,4 +90,12 @@ public boolean isLegacyYamlDeserialization() {
8990
public void setLegacyYamlDeserialization(boolean legacyYamlDeserialization) {
9091
this.legacyYamlDeserialization = legacyYamlDeserialization;
9192
}
93+
94+
public void setValidateInternalRefs(boolean validateInternalRefs) {
95+
this.validateInternalRefs = validateInternalRefs;
96+
}
97+
98+
public boolean isValidateInternalRefs() {
99+
return validateInternalRefs;
100+
}
92101
}

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,9 @@ public class OpenAPIDeserializer {
139139
private static final String REFERENCE_SEPARATOR = "#/";
140140
private Components components;
141141
private final Set<String> operationIDs = new HashSet<>();
142+
private Map<String,String> localSchemaRefs = new HashMap<>();
142143

143-
public SwaggerParseResult deserialize(JsonNode rootNode) {
144+
public SwaggerParseResult deserialize(JsonNode rootNode) {
144145
return deserialize(rootNode, null);
145146
}
146147

@@ -152,6 +153,7 @@ public SwaggerParseResult deserialize(JsonNode rootNode, String path, ParseOptio
152153
SwaggerParseResult result = new SwaggerParseResult();
153154
ParseResult rootParse = new ParseResult();
154155
rootParse.setAllowEmptyStrings(options.isAllowEmptyString());
156+
rootParse.setValidateInternalRefs(options.isValidateInternalRefs());
155157
OpenAPI api = parseRoot(rootNode, rootParse, path);
156158
result.setOpenAPI(api);
157159
result.setMessages(rootParse.getMessages());
@@ -184,6 +186,13 @@ public OpenAPI parseRoot(JsonNode node, ParseResult result, String path) {
184186
Components components = getComponents(obj, "components", result);
185187
openAPI.setComponents(components);
186188
this.components = components;
189+
if(result.validateInternalRefs) {
190+
for (String schema : localSchemaRefs.keySet()) {
191+
if (components.getSchemas().get(schema) == null) {
192+
result.invalidType(localSchemaRefs.get(schema), schema, "schema", rootNode);
193+
}
194+
}
195+
}
187196
}
188197

189198
obj = getObject("paths", rootNode, true, location, result);
@@ -2292,6 +2301,10 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result) {
22922301
} else {
22932302
schema.set$ref(ref.asText());
22942303
}
2304+
if(schema.get$ref().startsWith("#/components/schemas")){// it's internal
2305+
String refName = schema.get$ref().substring(schema.get$ref().lastIndexOf("/")+1);
2306+
localSchemaRefs.put(refName,location);
2307+
}
22952308
return schema;
22962309
} else {
22972310
result.invalidType(location, "$ref", "string", node);
@@ -3185,6 +3198,7 @@ public static class ParseResult {
31853198
private List<Location> unique = new ArrayList<>();
31863199
private List<Location> uniqueTags = new ArrayList<>();
31873200
private boolean allowEmptyStrings = true;
3201+
private boolean validateInternalRefs;
31883202

31893203
public ParseResult() {
31903204
}
@@ -3279,7 +3293,15 @@ public List<String> getMessages() {
32793293
}
32803294
return messages;
32813295
}
3282-
}
3296+
3297+
public void setValidateInternalRefs(boolean validateInternalRefs) {
3298+
this.validateInternalRefs = validateInternalRefs;
3299+
}
3300+
3301+
public boolean isValidateInternalRefs() {
3302+
return validateInternalRefs;
3303+
}
3304+
}
32833305

32843306

32853307
protected static class Location {

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,93 @@ public class OpenAPIV3ParserTest {
8585
protected int serverPort = getDynamicPort();
8686
protected WireMockServer wireMockServer;
8787

88+
@Test
89+
public void testIssue1643_True() throws Exception{
90+
ParseOptions options = new ParseOptions();
91+
options.setValidateInternalRefs(true);
92+
String issue1643 = "openapi: \"3.0.0\"\n" +
93+
"info:\n" +
94+
" version: 1.0.0\n" +
95+
" title: People\n" +
96+
"paths:\n" +
97+
" /person:\n" +
98+
" get:\n" +
99+
" operationId: getPerson\n" +
100+
" parameters:\n" +
101+
" - name: name\n" +
102+
" in: query\n" +
103+
" required: true\n" +
104+
" schema:\n" +
105+
" type: string\n" +
106+
" responses:\n" +
107+
" '200':\n" +
108+
" description: The person with the given name. \n" +
109+
" content:\n" +
110+
" application/json:\n" +
111+
" schema:\n" +
112+
" $ref: '#/components/schemas/Person'\n" +
113+
"components:\n" +
114+
" schemas:\n" +
115+
" Person:\n" +
116+
" required:\n" +
117+
" - name\n" +
118+
" type: object\n" +
119+
" properties:\n" +
120+
" name:\n" +
121+
" type: string\n" +
122+
" employee:\n" +
123+
" $ref: '#/components/schemas/Employee'";
124+
SwaggerParseResult result = new OpenAPIV3Parser().readContents(issue1643, null, options);
125+
126+
Assert.assertNotNull(result);
127+
Assert.assertNotNull(result.getOpenAPI());
128+
assertEquals(result.getMessages().size(),1);
129+
assertTrue(result.getMessages().contains("attribute components.schemas.Person.Employee is not of type `schema`"));
130+
}
131+
132+
@Test
133+
public void testIssue1643_False() throws Exception{
134+
ParseOptions options = new ParseOptions();
135+
String issue1643 = "openapi: \"3.0.0\"\n" +
136+
"info:\n" +
137+
" version: 1.0.0\n" +
138+
" title: People\n" +
139+
"paths:\n" +
140+
" /person:\n" +
141+
" get:\n" +
142+
" operationId: getPerson\n" +
143+
" parameters:\n" +
144+
" - name: name\n" +
145+
" in: query\n" +
146+
" required: true\n" +
147+
" schema:\n" +
148+
" type: string\n" +
149+
" responses:\n" +
150+
" '200':\n" +
151+
" description: The person with the given name. \n" +
152+
" content:\n" +
153+
" application/json:\n" +
154+
" schema:\n" +
155+
" $ref: '#/components/schemas/Person'\n" +
156+
"components:\n" +
157+
" schemas:\n" +
158+
" Person:\n" +
159+
" required:\n" +
160+
" - name\n" +
161+
" type: object\n" +
162+
" properties:\n" +
163+
" name:\n" +
164+
" type: string\n" +
165+
" employee:\n" +
166+
" $ref: '#/components/schemas/Employee'";
167+
SwaggerParseResult result = new OpenAPIV3Parser().readContents(issue1643, null, options);
168+
169+
Assert.assertNotNull(result);
170+
Assert.assertNotNull(result.getOpenAPI());
171+
assertEquals(result.getMessages().size(),0);
172+
assertFalse(result.getMessages().contains("attribute components.schemas.Person.Employee is not of type `schema`"));
173+
}
174+
88175
@Test
89176
public void testExampleFormatByte() throws Exception{
90177

0 commit comments

Comments
 (0)