Skip to content

Commit 98e8a4e

Browse files
committed
Prevent NPE from missing schema on Component. Improve exception handling.
1 parent 08a7630 commit 98e8a4e

File tree

2 files changed

+98
-2
lines changed

2 files changed

+98
-2
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,11 @@ public SwaggerParseResult deserialize(JsonNode rootNode, String path, ParseOptio
299299
result.setOpenAPI(api);
300300
result.setMessages(rootParse.getMessages());
301301
} catch (Exception e) {
302-
result.setMessages(Arrays.asList(e.getMessage()));
302+
if (StringUtils.isNotBlank(e.getMessage())) {
303+
result.setMessages(Arrays.asList(e.getMessage()));
304+
} else {
305+
result.setMessages(Arrays.asList("Unexpected error deserialising spec"));
306+
}
303307
}
304308
return result;
305309
}
@@ -343,10 +347,13 @@ public OpenAPI parseRoot(JsonNode node, ParseResult result, String path) {
343347
* e.g. #/components/schemas/foo/properties/bar
344348
*/
345349
for (String schema : localSchemaRefs.keySet()) {
346-
if (components.getSchemas().get(schema) == null) {
350+
if (components.getSchemas() == null){
351+
result.missing(localSchemaRefs.get(schema), schema);
352+
} else if (components.getSchemas().get(schema) == null) {
347353
result.invalidType(localSchemaRefs.get(schema), schema, "schema", rootNode);
348354
}
349355
}
356+
350357
}
351358
}
352359

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
package io.swagger.v3.parser.test;
22

33

4+
import io.swagger.v3.core.util.Yaml;
5+
import io.swagger.v3.oas.models.Components;
6+
import io.swagger.v3.oas.models.OpenAPI;
7+
import io.swagger.v3.oas.models.Operation;
8+
import io.swagger.v3.oas.models.PathItem;
9+
import io.swagger.v3.oas.models.Paths;
10+
import io.swagger.v3.oas.models.SpecVersion;
11+
import io.swagger.v3.oas.models.media.ComposedSchema;
12+
import io.swagger.v3.oas.models.media.Content;
13+
import io.swagger.v3.oas.models.media.MediaType;
14+
import io.swagger.v3.oas.models.media.ObjectSchema;
15+
import io.swagger.v3.oas.models.media.StringSchema;
16+
import io.swagger.v3.oas.models.parameters.RequestBody;
17+
import io.swagger.v3.oas.models.responses.ApiResponse;
18+
import io.swagger.v3.oas.models.responses.ApiResponses;
419
import io.swagger.v3.parser.core.models.ParseOptions;
520
import io.swagger.v3.parser.core.models.SwaggerParseResult;
621
import io.swagger.v3.parser.OpenAPIV3Parser;
722
import org.testng.annotations.Test;
823

24+
import java.util.HashMap;
25+
926
import static org.testng.Assert.assertNotNull;
27+
import static org.testng.Assert.assertTrue;
1028
import static org.testng.AssertJUnit.assertEquals;
1129

1230
public class OAIDeserializationTest {
@@ -42,4 +60,75 @@ public void testIssue911() {
4260
assertEquals(result.getMessages().size(),1);
4361
assertNotNull(result.getOpenAPI());
4462
}
63+
64+
@Test
65+
public void testDeserializeYamlDefinition() throws Exception {
66+
OpenAPI api = new OpenAPI();
67+
api.setSpecVersion(SpecVersion.V30);
68+
api.setComponents(new Components());
69+
ApiResponse errorResponse = new ApiResponse();
70+
errorResponse.setContent(new Content());
71+
errorResponse.setDescription("asdad");
72+
MediaType errorType = new MediaType();
73+
errorResponse.getContent().addMediaType("application/json", errorType);
74+
// ObjectSchema errorObjType = new ObjectSchema();
75+
// errorObjType.addProperty("code", new StringSchema());
76+
// errorType.setSchema(errorObjType);
77+
errorType.setSchema(new ComposedSchema().$ref("NotAddedYet").type("schema"));
78+
api.getComponents().setResponses(new HashMap<>());
79+
api.getComponents().getResponses().put("ErrorObj", errorResponse);
80+
Paths path = new Paths();
81+
PathItem pathItem = new PathItem();
82+
Operation post = new Operation();
83+
RequestBody body = new RequestBody();
84+
Content content = new Content();
85+
MediaType type = new MediaType();
86+
ApiResponses resp = new ApiResponses();
87+
resp.addApiResponse("401", new ApiResponse().$ref("#/components/responses/ErrorObj"));
88+
// resp.addApiResponse("401", new ApiResponse().description("Bad request").content(new Content().addMediaType("application/json", new MediaType().schema(new ComposedSchema().$ref("#/components/responses/ErrorObj")))));
89+
resp.setDefault(new ApiResponse().description("Default response is just a string").content(new Content().addMediaType("application/json", new MediaType().schema(new StringSchema()))));
90+
post.setResponses(resp);
91+
ComposedSchema schema = new ComposedSchema();
92+
schema.set$ref("ThingRequest");
93+
schema.setType("schema");
94+
// type.setSchema(new ObjectSchema().addProperty("mything", new StringSchema()));
95+
type.setSchema(schema);
96+
content.addMediaType("application/json", type);
97+
body.setContent(content);
98+
post.setRequestBody(body);
99+
pathItem.post(post);
100+
path.addPathItem("/thingy", pathItem);
101+
api.setPaths(path);
102+
String yaml = Yaml.mapper().writeValueAsString(api);
103+
System.out.println(yaml);
104+
105+
// openapi: 3.0.1
106+
// paths:
107+
// /thingy:
108+
// post:
109+
// requestBody:
110+
// content:
111+
// application/json:
112+
// schema:
113+
// $ref: '#/components/schemas/ThingRequest'
114+
// components:
115+
// responses:
116+
// ErrorObj:
117+
// content:
118+
// application/json:
119+
// schema:
120+
// type: object
121+
// properties:
122+
// code:
123+
// type: string
124+
125+
ParseOptions options = new ParseOptions();
126+
options.setResolve(true);
127+
SwaggerParseResult result = new OpenAPIV3Parser().readContents(yaml, null, options);
128+
129+
assertNotNull(result.getOpenAPI());
130+
assertTrue(result.getMessages().contains("attribute info is missing"));
131+
assertTrue(result.getMessages().contains("attribute components.responses.ErrorObj.content.'application/json'.schema.NotAddedYet is missing"));
132+
assertTrue(result.getMessages().contains("attribute paths.'/thingy'(post).requestBody.content.'application/json'.schema.#/components/schemas/ThingRequest is missing"));
133+
}
45134
}

0 commit comments

Comments
 (0)