Skip to content

Commit 2678258

Browse files
author
bnasslahsen
committed
Improve support of responses overloading. fixes #354
1 parent 8ff8e39 commit 2678258

File tree

6 files changed

+334
-12
lines changed

6 files changed

+334
-12
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractResponseBuilder.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,18 @@ protected AbstractResponseBuilder(OperationBuilder operationBuilder, List<Return
4949

5050
public ApiResponses build(Components components, HandlerMethod handlerMethod, Operation operation,
5151
MethodAttributes methodAttributes) {
52-
final ApiResponses apiResponses = getApiResponses(operation);
53-
// for each one build ApiResponse and add it to existing responses
52+
ApiResponses apiResponses = new ApiResponses();
5453
genericMapResponse.forEach(apiResponses::addApiResponse);
54+
//Then use the apiResponses from documentation
55+
ApiResponses apiResponsesFromDoc = operation.getResponses();
56+
if (apiResponsesFromDoc != null)
57+
apiResponsesFromDoc.forEach(apiResponses::addApiResponse);
58+
// for each one build ApiResponse and add it to existing responses
5559
// Fill api Responses
5660
computeResponse(components, handlerMethod.getMethod(), apiResponses, methodAttributes, false);
5761
return apiResponses;
5862
}
5963

60-
private ApiResponses getApiResponses(Operation operation) {
61-
ApiResponses apiResponses = operation.getResponses();
62-
if (apiResponses == null)
63-
apiResponses = new ApiResponses();
64-
return apiResponses;
65-
}
66-
6764
public void buildGenericResponse(Components components, Map<String, Object> findControllerAdvice) {
6865
// ControllerAdvice
6966
List<Method> methods = getMethods(findControllerAdvice);
@@ -149,8 +146,11 @@ private void buildContentFromDoc(Components components, ApiResponses apiResponse
149146
Content existingContent = apiResponsesOp.get(apiResponseAnnotations.responseCode()).getContent();
150147
if (optionalContent.isPresent() && existingContent != null) {
151148
Content newContent = optionalContent.get();
152-
Arrays.stream(methodAttributes.getAllProduces()).filter(mediaTypeStr -> (newContent.get(mediaTypeStr) != null)).forEach(mediaTypeStr -> mergeSchema(existingContent, newContent.get(mediaTypeStr).getSchema(), mediaTypeStr));
153-
apiResponse.content(existingContent);
149+
if (methodAttributes.isMethodOverloaded()) {
150+
Arrays.stream(methodAttributes.getAllProduces()).filter(mediaTypeStr -> (newContent.get(mediaTypeStr) != null)).forEach(mediaTypeStr -> mergeSchema(existingContent, newContent.get(mediaTypeStr).getSchema(), mediaTypeStr));
151+
apiResponse.content(existingContent);
152+
} else
153+
apiResponse.content(newContent);
154154
}
155155
} else {
156156
optionalContent.ifPresent(apiResponse::content);
@@ -224,7 +224,7 @@ private Content buildContent(Components components, Method method, String[] meth
224224

225225
private Type getReturnType(Method method) {
226226
Type returnType = Object.class;
227-
for (ReturnTypeParser returnTypeParser: returnTypeParsers) {
227+
for (ReturnTypeParser returnTypeParser : returnTypeParsers) {
228228
if (returnType.getTypeName().equals(Object.class.getTypeName())) {
229229
returnType = returnTypeParser.getReturnType(method);
230230
} else {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package test.org.springdoc.api.app75;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.Parameter;
5+
import io.swagger.v3.oas.annotations.enums.ParameterIn;
6+
import io.swagger.v3.oas.annotations.media.Content;
7+
import io.swagger.v3.oas.annotations.media.Schema;
8+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
9+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
10+
import org.springframework.web.bind.annotation.PostMapping;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
@RestController
14+
public class HelloController {
15+
16+
@PostMapping("/test1")
17+
@Operation(summary = "Example api that realize an ECHO operation",
18+
description = "The result of the echo is the input value of the api",
19+
parameters = {@Parameter(in = ParameterIn.PATH,
20+
name = "uuid",
21+
required = true,
22+
description = "Is the identification of the document",
23+
schema = @Schema(type = "string",
24+
example = "uuid"))}
25+
26+
27+
)
28+
@ApiResponses(value = {
29+
@ApiResponse(description = "Successful Operation",
30+
responseCode = "200",
31+
content = @Content(mediaType = "application/json",
32+
schema = @Schema(implementation = PersonDTO.class))),
33+
@ApiResponse(responseCode = "201",
34+
description = "other possible response")
35+
})
36+
public String postMyRequestBody1() {
37+
return null;
38+
}
39+
40+
@PostMapping("/test2")
41+
@Operation(summary = "Example api that realize an ECHO operation",
42+
description = "The result of the echo is the input value of the api",
43+
responses = {
44+
@ApiResponse(description = "Successful Operation",
45+
responseCode = "200",
46+
content = @Content(mediaType = "application/json",
47+
schema = @Schema(implementation = PersonDTO.class))),
48+
@ApiResponse(responseCode = "201",
49+
description = "other possible response")
50+
},
51+
parameters = {@Parameter(in = ParameterIn.PATH,
52+
name = "uuid",
53+
required = true,
54+
description = "Is the identification of the document",
55+
schema = @Schema(type = "string",
56+
example = "uuid"))}
57+
58+
59+
)
60+
public String postMyRequestBody2() {
61+
return null;
62+
}
63+
64+
@PostMapping("/test3")
65+
@Operation(summary = "Example api that realize an ECHO operation",
66+
description = "The result of the echo is the input value of the api",
67+
parameters = {@Parameter(in = ParameterIn.PATH,
68+
name = "uuid",
69+
required = true,
70+
description = "Is the identification of the document",
71+
schema = @Schema(type = "string",
72+
example = "uuid"))}
73+
74+
75+
)
76+
@ApiResponse(responseCode = "201",
77+
description = "other possible response")
78+
public String postMyRequestBody3() {
79+
return null;
80+
}
81+
82+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package test.org.springdoc.api.app75;
2+
3+
public class PersonDTO {
4+
private String email;
5+
private String firstName;
6+
private String lastName;
7+
8+
public PersonDTO() {
9+
}
10+
11+
public PersonDTO(final String email, final String firstName, final String lastName) {
12+
this.email = email;
13+
this.firstName = firstName;
14+
this.lastName = lastName;
15+
}
16+
17+
public String getEmail() {
18+
return email;
19+
}
20+
21+
public void setEmail(final String email) {
22+
this.email = email;
23+
}
24+
25+
public String getFirstName() {
26+
return firstName;
27+
}
28+
29+
public void setFirstName(final String firstName) {
30+
this.firstName = firstName;
31+
}
32+
33+
public String getLastName() {
34+
return lastName;
35+
}
36+
37+
public void setLastName(final String lastName) {
38+
this.lastName = lastName;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package test.org.springdoc.api.app75;
2+
3+
import org.springframework.http.HttpStatus;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.ControllerAdvice;
6+
import org.springframework.web.bind.annotation.ExceptionHandler;
7+
import org.springframework.web.bind.annotation.ResponseStatus;
8+
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
9+
10+
import javax.servlet.http.HttpServletRequest;
11+
import java.util.List;
12+
13+
@ControllerAdvice
14+
public class RestResponseEntityExceptionHandler
15+
extends ResponseEntityExceptionHandler {
16+
@ResponseStatus(value = HttpStatus.OK)
17+
@ExceptionHandler({Exception.class})
18+
public ResponseEntity<List<Object>> badRequest(HttpServletRequest req, Exception exception) {
19+
return null;
20+
}
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package test.org.springdoc.api.app75;
2+
3+
import org.springframework.boot.autoconfigure.SpringBootApplication;
4+
import test.org.springdoc.api.AbstractSpringDocTest;
5+
6+
public class SpringDocApp75Test extends AbstractSpringDocTest {
7+
8+
@SpringBootApplication
9+
static class SpringDocTestApp {
10+
}
11+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/test3": {
15+
"post": {
16+
"tags": [
17+
"hello-controller"
18+
],
19+
"summary": "Example api that realize an ECHO operation",
20+
"description": "The result of the echo is the input value of the api",
21+
"operationId": "postMyRequestBody3",
22+
"parameters": [
23+
{
24+
"name": "uuid",
25+
"in": "path",
26+
"description": "Is the identification of the document",
27+
"required": true,
28+
"schema": {
29+
"type": "string",
30+
"example": "uuid"
31+
}
32+
}
33+
],
34+
"responses": {
35+
"200": {
36+
"description": "default response",
37+
"content": {
38+
"*/*": {
39+
"schema": {
40+
"type": "array",
41+
"items": {
42+
"type": "object"
43+
}
44+
}
45+
}
46+
}
47+
},
48+
"201": {
49+
"description": "other possible response",
50+
"content": {
51+
"*/*": {
52+
"schema": {
53+
"type": "string"
54+
}
55+
}
56+
}
57+
}
58+
}
59+
}
60+
},
61+
"/test1": {
62+
"post": {
63+
"tags": [
64+
"hello-controller"
65+
],
66+
"summary": "Example api that realize an ECHO operation",
67+
"description": "The result of the echo is the input value of the api",
68+
"operationId": "postMyRequestBody1",
69+
"parameters": [
70+
{
71+
"name": "uuid",
72+
"in": "path",
73+
"description": "Is the identification of the document",
74+
"required": true,
75+
"schema": {
76+
"type": "string",
77+
"example": "uuid"
78+
}
79+
}
80+
],
81+
"responses": {
82+
"200": {
83+
"description": "Successful Operation",
84+
"content": {
85+
"application/json": {
86+
"schema": {
87+
"$ref": "#/components/schemas/PersonDTO"
88+
}
89+
}
90+
}
91+
},
92+
"201": {
93+
"description": "other possible response",
94+
"content": {
95+
"*/*": {
96+
"schema": {
97+
"type": "string"
98+
}
99+
}
100+
}
101+
}
102+
}
103+
}
104+
},
105+
"/test2": {
106+
"post": {
107+
"tags": [
108+
"hello-controller"
109+
],
110+
"summary": "Example api that realize an ECHO operation",
111+
"description": "The result of the echo is the input value of the api",
112+
"operationId": "postMyRequestBody2",
113+
"parameters": [
114+
{
115+
"name": "uuid",
116+
"in": "path",
117+
"description": "Is the identification of the document",
118+
"required": true,
119+
"schema": {
120+
"type": "string",
121+
"example": "uuid"
122+
}
123+
}
124+
],
125+
"responses": {
126+
"200": {
127+
"description": "Successful Operation",
128+
"content": {
129+
"application/json": {
130+
"schema": {
131+
"$ref": "#/components/schemas/PersonDTO"
132+
}
133+
}
134+
}
135+
},
136+
"201": {
137+
"description": "other possible response",
138+
"content": {
139+
"*/*": {
140+
"schema": {
141+
"type": "string"
142+
}
143+
}
144+
}
145+
}
146+
}
147+
}
148+
}
149+
},
150+
"components": {
151+
"schemas": {
152+
"PersonDTO": {
153+
"type": "object",
154+
"properties": {
155+
"email": {
156+
"type": "string"
157+
},
158+
"firstName": {
159+
"type": "string"
160+
},
161+
"lastName": {
162+
"type": "string"
163+
}
164+
}
165+
}
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)