Skip to content

Commit 5ced0b5

Browse files
author
bnasslahsen
committed
Only extend defined ApiResponses with generic responses from controller advice. Fixes #429
1 parent 571af8f commit 5ced0b5

File tree

5 files changed

+84
-20
lines changed

5 files changed

+84
-20
lines changed

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/GenericResponseBuilder.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public class GenericResponseBuilder {
7070
super();
7171
this.operationBuilder = operationBuilder;
7272
this.returnTypeParsers = returnTypeParsers;
73-
this.springDocConfigProperties=springDocConfigProperties;
73+
this.springDocConfigProperties = springDocConfigProperties;
7474
}
7575

7676
public ApiResponses build(Components components, HandlerMethod handlerMethod, Operation operation,
@@ -125,6 +125,9 @@ private Map<String, ApiResponse> computeResponse(Components components, Method m
125125
Set<io.swagger.v3.oas.annotations.responses.ApiResponse> responsesArray = getApiResponses(method);
126126
if (!responsesArray.isEmpty()) {
127127
methodAttributes.setWithApiResponseDoc(true);
128+
if (!springDocConfigProperties.isOverrideWithGenericResponse())
129+
for (String key : genericMapResponse.keySet())
130+
apiResponsesOp.remove(key);
128131
for (io.swagger.v3.oas.annotations.responses.ApiResponse apiResponseAnnotations : responsesArray) {
129132
ApiResponse apiResponse = new ApiResponse();
130133
if (StringUtils.isNotBlank(apiResponseAnnotations.ref())) {
@@ -258,7 +261,7 @@ private Schema<?> calculateSchema(Components components, Type returnType, JsonVi
258261
// if void, no content
259262
return null;
260263
}
261-
Schema<?> schemaN = SpringDocAnnotationsUtils.extractSchema(components, returnType, jsonView);
264+
Schema<?> schemaN = SpringDocAnnotationsUtils.extractSchema(components, returnType, jsonView);
262265
if (schemaN == null && returnType instanceof Class && !isResponseTypeToIgnore((Class) returnType)) {
263266
schemaN = AnnotationsUtils.resolveSchemaFromType((Class) returnType, null, jsonView);
264267
}

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java

+10
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ public class SpringDocConfigProperties {
5555

5656
private boolean modelAndViewAllowed;
5757

58+
private boolean overrideWithGenericResponse = true;
59+
5860
private String defaultConsumesMediaType = MediaType.APPLICATION_JSON_VALUE;
5961

6062
private String defaultProducesMediaType = MediaType.ALL_VALUE;
@@ -303,4 +305,12 @@ public String getDefaultProducesMediaType() {
303305
public void setDefaultProducesMediaType(String defaultProducesMediaType) {
304306
this.defaultProducesMediaType = defaultProducesMediaType;
305307
}
308+
309+
public boolean isOverrideWithGenericResponse() {
310+
return overrideWithGenericResponse;
311+
}
312+
313+
public void setOverrideWithGenericResponse(boolean overrideWithGenericResponse) {
314+
this.overrideWithGenericResponse = overrideWithGenericResponse;
315+
}
306316
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package test.org.springdoc.api.app91;
22

33
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
5+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
46
import io.swagger.v3.oas.annotations.tags.Tag;
57
import org.apache.commons.lang3.RandomStringUtils;
68

79
import org.springframework.http.ResponseEntity;
810
import org.springframework.web.bind.annotation.GetMapping;
9-
import org.springframework.web.bind.annotation.RequestMapping;
1011
import org.springframework.web.bind.annotation.RestController;
1112

1213
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
1314

1415
@RestController
15-
@RequestMapping(produces = APPLICATION_JSON_VALUE)
1616
@Tag(name = "Demo", description = "The Demo API")
1717
public class GreetingController {
1818

@@ -21,4 +21,13 @@ public class GreetingController {
2121
public ResponseEntity<Greeting> sayHello() {
2222
return ResponseEntity.ok(new Greeting(RandomStringUtils.randomAlphanumeric(10)));
2323
}
24+
25+
@GetMapping("/test")
26+
@ApiResponses(value = { @ApiResponse(responseCode = "201", description = "item created"),
27+
@ApiResponse(responseCode = "400", description = "invalid input, object invalid"),
28+
@ApiResponse(responseCode = "409", description = "an existing item already exists") })
29+
public ResponseEntity<Greeting> sayHello2() {
30+
return ResponseEntity.ok(new Greeting(RandomStringUtils.randomAlphanumeric(10)));
31+
}
32+
2433
}

Diff for: springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app91/SpringDocApp91Test.java

+2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import test.org.springdoc.api.AbstractSpringDocTest;
2323

2424
import org.springframework.boot.autoconfigure.SpringBootApplication;
25+
import org.springframework.test.context.TestPropertySource;
2526

27+
@TestPropertySource(properties = "springdoc.override-with-generic-response=false")
2628
public class SpringDocApp91Test extends AbstractSpringDocTest {
2729

2830
@SpringBootApplication

Diff for: springdoc-openapi-webmvc-core/src/test/resources/results/app91.json

+56-16
Original file line numberDiff line numberDiff line change
@@ -25,42 +25,42 @@
2525
"summary": "This API will return a random greeting.",
2626
"operationId": "sayHello",
2727
"responses": {
28-
"500": {
29-
"description": "Internal Server Error",
28+
"400": {
29+
"description": "Bad Request",
3030
"content": {
3131
"application/json": {
3232
"schema": {
3333
"$ref": "#/components/schemas/ApiError"
3434
},
3535
"examples": {
36-
"Service-500": {
37-
"summary": "500 from the service directly",
38-
"description": "Service-500",
36+
"Service-400": {
37+
"summary": "400 from the service directly",
38+
"description": "Service-400",
3939
"value": {
40-
"status": 500,
41-
"errorCode": "ERROR_002",
42-
"message": "Another example message..."
40+
"status": 400,
41+
"errorCode": "ERROR_001",
42+
"message": "An example message..."
4343
}
4444
}
4545
}
4646
}
4747
}
4848
},
49-
"400": {
50-
"description": "Bad Request",
49+
"500": {
50+
"description": "Internal Server Error",
5151
"content": {
5252
"application/json": {
5353
"schema": {
5454
"$ref": "#/components/schemas/ApiError"
5555
},
5656
"examples": {
57-
"Service-400": {
58-
"summary": "400 from the service directly",
59-
"description": "Service-400",
57+
"Service-500": {
58+
"summary": "500 from the service directly",
59+
"description": "Service-500",
6060
"value": {
61-
"status": 400,
62-
"errorCode": "ERROR_001",
63-
"message": "An example message..."
61+
"status": 500,
62+
"errorCode": "ERROR_002",
63+
"message": "Another example message..."
6464
}
6565
}
6666
}
@@ -79,6 +79,46 @@
7979
}
8080
}
8181
}
82+
},
83+
"/test": {
84+
"get": {
85+
"tags": [
86+
"Demo"
87+
],
88+
"operationId": "sayHello2",
89+
"responses": {
90+
"400": {
91+
"description": "invalid input, object invalid",
92+
"content": {
93+
"*/*": {
94+
"schema": {
95+
"$ref": "#/components/schemas/Greeting"
96+
}
97+
}
98+
}
99+
},
100+
"201": {
101+
"description": "item created",
102+
"content": {
103+
"*/*": {
104+
"schema": {
105+
"$ref": "#/components/schemas/Greeting"
106+
}
107+
}
108+
}
109+
},
110+
"409": {
111+
"description": "an existing item already exists",
112+
"content": {
113+
"*/*": {
114+
"schema": {
115+
"$ref": "#/components/schemas/Greeting"
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
82122
}
83123
},
84124
"components": {

0 commit comments

Comments
 (0)