Skip to content

Commit 4f58976

Browse files
committed
allow non explicit style and explode with 'explicitStyleAndExplode' option
1 parent d395885 commit 4f58976

File tree

4 files changed

+236
-11
lines changed

4 files changed

+236
-11
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class ParseOptions {
2121
private boolean safelyResolveURL;
2222
private List<String> remoteRefAllowList;
2323
private List<String> remoteRefBlockList;
24+
private boolean explicitStyleAndExplode = true;
2425

2526

2627
public boolean isResolve() {
@@ -169,4 +170,13 @@ public boolean isResolveResponses() {
169170
public void setResolveResponses(boolean resolveResponses) {
170171
this.resolveResponses = resolveResponses;
171172
}
173+
174+
public boolean isExplicitStyleAndExplode() {
175+
return explicitStyleAndExplode;
176+
}
177+
178+
public void setExplicitStyleAndExplode(boolean explicitStyleAndExplode) {
179+
this.explicitStyleAndExplode = explicitStyleAndExplode;
180+
}
181+
172182
}

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

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ public SwaggerParseResult deserialize(JsonNode rootNode, String path, ParseOptio
305305
rootParse.setInferSchemaType(options.isInferSchemaType());
306306
rootParse.setAllowEmptyStrings(options.isAllowEmptyString());
307307
rootParse.setValidateInternalRefs(options.isValidateInternalRefs());
308+
rootParse.setExplicitStyleAndExplode(options.isExplicitStyleAndExplode());
308309
OpenAPI api = parseRoot(rootNode, rootParse, path);
309310
result.openapi31(rootParse.isOpenapi31());
310311
result.setOpenAPI(api);
@@ -1520,7 +1521,9 @@ public Encoding getEncoding(ObjectNode node, String location, ParseResult result
15201521
value = getString("style", node, false, location, result);
15211522

15221523
if (StringUtils.isBlank(value)) {
1523-
encoding.setStyle(Encoding.StyleEnum.FORM);
1524+
if (result.isExplicitStyleAndExplode()) {
1525+
encoding.setStyle(Encoding.StyleEnum.FORM);
1526+
}
15241527
} else {
15251528
if (value.equals(Encoding.StyleEnum.FORM.toString())) {
15261529
encoding.setStyle(Encoding.StyleEnum.FORM);
@@ -2131,9 +2134,9 @@ else if(parameter.getSchema() == null) {
21312134
Boolean explode = getBoolean("explode", obj, false, location, result);
21322135
if (explode != null) {
21332136
parameter.setExplode(explode);
2134-
} else if (StyleEnum.FORM.equals(parameter.getStyle())) {
2137+
} else if (StyleEnum.FORM.equals(parameter.getStyle()) && result.isExplicitStyleAndExplode()) {
21352138
parameter.setExplode(Boolean.TRUE);
2136-
} else {
2139+
} else if (result.isExplicitStyleAndExplode()){
21372140
parameter.setExplode(Boolean.FALSE);
21382141
}
21392142
}
@@ -2237,15 +2240,26 @@ public Header getHeader(ObjectNode headerNode, String location, ParseResult resu
22372240
header.setDeprecated(deprecated);
22382241
}
22392242

2243+
String style = getString("style", headerNode, false, location, result);
2244+
if (StringUtils.isBlank(style)) {
2245+
if (result.isExplicitStyleAndExplode()) {
2246+
header.setStyle(Header.StyleEnum.SIMPLE);
2247+
}
2248+
} else {
2249+
if (value.equals(Header.StyleEnum.SIMPLE.toString())) {
2250+
header.setStyle(Header.StyleEnum.SIMPLE);
2251+
} else {
2252+
result.invalidType(location, "style", "simple", headerNode);
2253+
}
2254+
}
2255+
22402256
Boolean explode = getBoolean("explode", headerNode, false, location, result);
22412257
if (explode != null) {
22422258
header.setExplode(explode);
2243-
} else {
2259+
} else if (result.isExplicitStyleAndExplode()){
22442260
header.setExplode(Boolean.FALSE);
22452261
}
22462262

2247-
header.setStyle(Header.StyleEnum.SIMPLE);
2248-
22492263
ObjectNode headerObject = getObject("schema", headerNode, false, location, result);
22502264
if (headerObject != null) {
22512265
header.setSchema(getSchema(headerObject, location, result));
@@ -3369,11 +3383,13 @@ public Example getExample(ObjectNode node, String location, ParseResult result)
33693383

33703384
public void setStyle(String value, Parameter parameter, String location, ObjectNode obj, ParseResult result) {
33713385
if (StringUtils.isBlank(value)) {
3372-
if (QUERY_PARAMETER.equals(parameter.getIn()) || COOKIE_PARAMETER.equals(parameter.getIn())) {
3373-
parameter.setStyle(StyleEnum.FORM);
3374-
} else if (PATH_PARAMETER.equals(parameter.getIn()) || HEADER_PARAMETER.equals(parameter.getIn())) {
3375-
parameter.setStyle(StyleEnum.SIMPLE);
3376-
}
3386+
if (result.isExplicitStyleAndExplode()) {
3387+
if (QUERY_PARAMETER.equals(parameter.getIn()) || COOKIE_PARAMETER.equals(parameter.getIn())) {
3388+
parameter.setStyle(StyleEnum.FORM);
3389+
} else if (PATH_PARAMETER.equals(parameter.getIn()) || HEADER_PARAMETER.equals(parameter.getIn())) {
3390+
parameter.setStyle(StyleEnum.SIMPLE);
3391+
}
3392+
}
33773393
} else {
33783394
if (value.equals(StyleEnum.FORM.toString())) {
33793395
parameter.setStyle(StyleEnum.FORM);
@@ -4275,6 +4291,8 @@ public static class ParseResult {
42754291
private boolean openapi31 = false;
42764292
private boolean oaiAuthor = false;
42774293

4294+
private boolean explicitStyleAndExplode = true;
4295+
42784296
public boolean isInferSchemaType() {
42794297
return inferSchemaType;
42804298
}
@@ -4370,6 +4388,19 @@ public ParseResult oaiAuthor(boolean oaiAuthor) {
43704388
return this;
43714389
}
43724390

4391+
public boolean isExplicitStyleAndExplode() {
4392+
return explicitStyleAndExplode;
4393+
}
4394+
4395+
public void setExplicitStyleAndExplode(boolean explicitStyleAndExplode) {
4396+
this.explicitStyleAndExplode = explicitStyleAndExplode;
4397+
}
4398+
4399+
public ParseResult explicitStyleAndExplode(boolean explicitStyleAndExplode) {
4400+
this.explicitStyleAndExplode = explicitStyleAndExplode;
4401+
return this;
4402+
}
4403+
43734404
public List<String> getMessages() {
43744405
List<String> messages = new ArrayList<String>();
43754406
for (Location l : extra.keySet()) {

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,6 +3362,63 @@ public void testResolveFullyResponses(){
33623362
SwaggerParseResult parseResult = openApiParser.readLocation("resolve-responses-test.yaml", null, options);
33633363
OpenAPI openAPI = parseResult.getOpenAPI();
33643364
assertNull(openAPI.getPaths().get("/users").getGet().getResponses().get("400").get$ref());
3365+
}
33653366

3367+
@Test(description = "style and explode should not be set with explicitStyleAndExplode = false")
3368+
public void testStyleAndExplodeNotExplicit(){
3369+
ParseOptions options = new ParseOptions();
3370+
options.setExplicitStyleAndExplode(false);
3371+
OpenAPIV3Parser openApiParser = new OpenAPIV3Parser();
3372+
SwaggerParseResult parseResult = openApiParser.readLocation("style-explode.yaml", null, options);
3373+
OpenAPI openAPI = parseResult.getOpenAPI();
3374+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(0).getStyle().toString(), "form");
3375+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(0).getExplode(), true);
3376+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(1).getStyle().toString(), "spaceDelimited");
3377+
assertNull(openAPI.getPaths().get("/test").getGet().getParameters().get(1).getExplode());
3378+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(2).getExplode(), true);
3379+
assertNull(openAPI.getPaths().get("/test").getGet().getParameters().get(2).getStyle());
3380+
assertNull(openAPI.getPaths().get("/test").getGet().getParameters().get(6).getStyle());
3381+
assertNull(openAPI.getPaths().get("/test").getGet().getParameters().get(6).getExplode());
3382+
assertNull(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("bar").getExplode());
3383+
assertNull(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("bar").getStyle());
3384+
assertEquals(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("foo").getExplode(), false);
3385+
assertNull(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("foo").getStyle());
3386+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("file").getStyle().toString(), "form");
3387+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("file").getExplode(), true);
3388+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyStyle").getStyle().toString(), "form");
3389+
assertNull(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyStyle").getExplode());
3390+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyExplode").getExplode(), true);
3391+
assertNull(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyExplode").getStyle());
3392+
assertNull(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithout").getStyle());
3393+
assertNull(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithout").getExplode());
3394+
}
3395+
3396+
@Test(description = "style and explode should be set with explicitStyleAndExplode = true")
3397+
public void testStyleAndExplodeExplicit(){
3398+
ParseOptions options = new ParseOptions();
3399+
options.setExplicitStyleAndExplode(true);
3400+
OpenAPIV3Parser openApiParser = new OpenAPIV3Parser();
3401+
SwaggerParseResult parseResult = openApiParser.readLocation("style-explode.yaml", null, options);
3402+
OpenAPI openAPI = parseResult.getOpenAPI();
3403+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(0).getStyle().toString(), "form");
3404+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(0).getExplode(), true);
3405+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(1).getStyle().toString(), "spaceDelimited");
3406+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(1).getExplode(), false);
3407+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(2).getStyle().toString(), "form");
3408+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(2).getExplode(), true);
3409+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(6).getStyle().toString(), "simple");
3410+
assertEquals(openAPI.getPaths().get("/test").getGet().getParameters().get(6).getExplode(), false);
3411+
assertEquals(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("bar").getExplode(), false);
3412+
assertEquals(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("bar").getStyle().toString(), "simple");
3413+
assertEquals(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("foo").getExplode(), false);
3414+
assertNull(openAPI.getPaths().get("/test").getGet().getResponses().get("200").getHeaders().get("foo").getStyle());
3415+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("file").getStyle().toString(), "form");
3416+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("file").getExplode(), true);
3417+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyStyle").getStyle().toString(), "form");
3418+
assertNull(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyStyle").getExplode());
3419+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyExplode").getExplode(), true);
3420+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithOnlyExplode").getStyle().toString(), "form");
3421+
assertEquals(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithout").getStyle().toString(), "form");
3422+
assertNull(openAPI.getPaths().get("/test").getPost().getRequestBody().getContent().get("multipart/form-data").getEncoding().get("fileWithout").getExplode());
33663423
}
33673424
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Example API with Style and Explode
4+
version: "1.0.0"
5+
paths:
6+
/test:
7+
get:
8+
summary: Demonstrate query and header parameters with style/explode variations
9+
parameters:
10+
# Query parameter with both style and explode
11+
- in: query
12+
name: foo
13+
style: form
14+
explode: true
15+
schema:
16+
type: array
17+
items:
18+
type: string
19+
20+
# Query parameter with only style
21+
- in: query
22+
name: bar
23+
style: spaceDelimited
24+
schema:
25+
type: array
26+
items:
27+
type: string
28+
29+
# Query parameter with only explode
30+
- in: query
31+
name: baz
32+
explode: true
33+
schema:
34+
type: array
35+
items:
36+
type: string
37+
38+
# Header parameter with both style and explode
39+
- in: header
40+
name: X-Foo
41+
style: simple
42+
explode: true
43+
schema:
44+
type: array
45+
items:
46+
type: string
47+
48+
# Header parameter with only style
49+
- in: header
50+
name: X-Bar
51+
style: simple
52+
schema:
53+
type: array
54+
items:
55+
type: string
56+
57+
# Header parameter with only explode
58+
- in: header
59+
name: X-Baz
60+
explode: true
61+
schema:
62+
type: array
63+
items:
64+
type: string
65+
66+
# Header parameter without
67+
- in: header
68+
name: X-FooBar
69+
schema:
70+
type: array
71+
items:
72+
type: string
73+
responses:
74+
'200':
75+
description: Success
76+
headers:
77+
foo:
78+
description: test
79+
style: form
80+
explode: false
81+
schema:
82+
type: array
83+
items:
84+
type: string
85+
bar:
86+
description: test
87+
schema:
88+
type: array
89+
items:
90+
type: string
91+
92+
post:
93+
summary: Demonstrate encoding with style/explode variations
94+
requestBody:
95+
content:
96+
multipart/form-data:
97+
schema:
98+
type: object
99+
properties:
100+
file:
101+
type: string
102+
format: binary
103+
fileWithOnlyStyle:
104+
type: string
105+
format: binary
106+
fileWithOnlyExplode:
107+
type: string
108+
format: binary
109+
fileWithout:
110+
type: string
111+
format: binary
112+
encoding:
113+
# Encoding with both style and explode
114+
file:
115+
style: form
116+
explode: true
117+
# Encoding with only style
118+
fileWithOnlyStyle:
119+
style: form
120+
# Encoding with only explode
121+
fileWithOnlyExplode:
122+
explode: true
123+
fileWithout:
124+
contentType: image/png, image/jpeg
125+
responses:
126+
'200':
127+
description: Success

0 commit comments

Comments
 (0)