Skip to content

Commit 20947e7

Browse files
author
springdoc
committed
fixes #185
1 parent 9969216 commit 20947e7

File tree

9 files changed

+222
-7
lines changed

9 files changed

+222
-7
lines changed

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

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@
77
import io.swagger.v3.oas.models.parameters.Parameter;
88
import org.apache.commons.lang3.StringUtils;
99
import org.springdoc.core.RequestInfo.ParameterType;
10+
import org.springframework.core.annotation.AnnotatedElementUtils;
1011
import org.springframework.util.CollectionUtils;
1112
import org.springframework.web.bind.annotation.*;
1213
import org.springframework.web.method.HandlerMethod;
1314

1415
import javax.validation.constraints.*;
1516
import java.lang.annotation.Annotation;
17+
import java.lang.reflect.Method;
1618
import java.math.BigDecimal;
1719
import java.util.*;
20+
import java.util.stream.Collectors;
21+
import java.util.stream.Stream;
1822

1923
import static org.springdoc.core.Constants.*;
2024

@@ -26,7 +30,7 @@ public abstract class AbstractRequestBuilder {
2630
// using string litterals to support both validation-api v1 and v2
2731
private static final String[] ANNOTATIONS_FOR_REQUIRED = {NotNull.class.getName(), "javax.validation.constraints.NotBlank", "javax.validation.constraints.NotEmpty"};
2832
private static final String POSITIVE_OR_ZERO = "javax.validation.constraints.PositiveOrZero";
29-
private static final String NEGATIVE_OR_ZERO= "javax.validation.constraints.NegativeOrZero";
33+
private static final String NEGATIVE_OR_ZERO = "javax.validation.constraints.NegativeOrZero";
3034

3135
protected AbstractRequestBuilder(AbstractParameterBuilder parameterBuilder, RequestBodyBuilder requestBodyBuilder,
3236
OperationBuilder operationBuilder) {
@@ -51,13 +55,17 @@ public Operation build(Components components, HandlerMethod handlerMethod, Reque
5155
RequestBodyInfo requestBodyInfo = new RequestBodyInfo(methodAttributes);
5256
List<Parameter> operationParameters = (operation.getParameters() != null) ? operation.getParameters()
5357
: new ArrayList<>();
58+
Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(handlerMethod.getMethod());
59+
5460
for (int i = 0; i < pNames.length; i++) {
5561
// check if query param
5662
Parameter parameter = null;
5763
final String pName = pNames[i];
5864
io.swagger.v3.oas.annotations.Parameter parameterDoc = parameterBuilder.getParameterAnnotation(
5965
handlerMethod, parameters[i], i, io.swagger.v3.oas.annotations.Parameter.class);
60-
66+
if (parameterDoc == null) {
67+
parameterDoc = parametersDocMap.get(pName);
68+
}
6169
// use documentation as reference
6270
if (parameterDoc != null) {
6371
if (parameterDoc.hidden()) {
@@ -69,7 +77,6 @@ public Operation build(Components components, HandlerMethod handlerMethod, Reque
6977

7078
if (!isParamToIgnore(parameters[i])) {
7179
ParameterInfo parameterInfo = new ParameterInfo(pName, parameters[i], parameter, i);
72-
7380
parameter = buildParams(parameterInfo, components, handlerMethod, requestMethod,
7481
methodAttributes.getJsonViewAnnotation());
7582
// Merge with the operation parameters
@@ -270,4 +277,27 @@ public RequestBodyBuilder getRequestBodyBuilder() {
270277
return requestBodyBuilder;
271278
}
272279

280+
private Map<String, io.swagger.v3.oas.annotations.Parameter> getApiParameters(Method method) {
281+
Class<?> declaringClass = method.getDeclaringClass();
282+
283+
Set<io.swagger.v3.oas.annotations.Parameters> apiParamerersDoc = AnnotatedElementUtils
284+
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameters.class);
285+
Map<String, io.swagger.v3.oas.annotations.Parameter> apiParamerersMap = apiParamerersDoc.stream()
286+
.flatMap(x -> Stream.of(x.value())).collect(Collectors.toMap(x -> x.name(), x -> x));
287+
288+
Set<io.swagger.v3.oas.annotations.Parameters> apiParametersDocDeclaringClass = AnnotatedElementUtils
289+
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameters.class);
290+
apiParamerersMap.putAll(apiParametersDocDeclaringClass.stream()
291+
.flatMap(x -> Stream.of(x.value())).collect(Collectors.toMap(x -> x.name(), x -> x)));
292+
293+
Set<io.swagger.v3.oas.annotations.Parameter> apiParamererDoc = AnnotatedElementUtils
294+
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameter.class);
295+
apiParamerersMap.putAll(apiParamererDoc.stream().collect(Collectors.toMap(x -> x.name(), x -> x)));
296+
297+
Set<io.swagger.v3.oas.annotations.Parameter> apiParameterDocDeclaringClass = AnnotatedElementUtils
298+
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameter.class);
299+
apiParamerersMap.putAll(apiParameterDocDeclaringClass.stream().collect(Collectors.toMap(x -> x.name(), x -> x)));
300+
301+
return apiParamerersMap;
302+
}
273303
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ private Set<io.swagger.v3.oas.annotations.responses.ApiResponse> getApiResponses
184184
.flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
185185

186186
Set<io.swagger.v3.oas.annotations.responses.ApiResponses> apiResponsesDocDeclaringClass = AnnotatedElementUtils
187-
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.responses.ApiResponses.class);
187+
.findAllMergedAnnotations(declaringClass, io.swagger.v3.oas.annotations.responses.ApiResponses.class);
188188
responses.addAll(
189189
apiResponsesDocDeclaringClass.stream().flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet()));
190190

springdoc-openapi-webflux-ui/src/test/java/test/org/springdoc/ui/app2/SpringDocApp2Test.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ public class SpringDocApp2Test {
2727
@Test
2828
public void shouldDisplaySwaggerUiPage() throws Exception {
2929
webTestClient.get().uri("/swagger-ui.html").exchange()
30-
.expectStatus().isTemporaryRedirect();
31-
webTestClient.get().uri("/persons?name=toto").exchange()
3230
.expectStatus().isNotFound();
33-
3431
}
3532

3633

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package test.org.springdoc.api.app60;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.Parameter;
5+
import io.swagger.v3.oas.annotations.Parameters;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RestController;
8+
9+
import java.util.List;
10+
11+
@RestController
12+
public class HelloController {
13+
14+
@GetMapping("/hello1")
15+
@Operation(summary = "summary1")
16+
@Parameters({
17+
@Parameter(name = "page", description = "The page"),
18+
@Parameter(name = "size", description = "The size")
19+
})
20+
public List<?> list1(String page, String size) {return null; }
21+
22+
@GetMapping("/hello2")
23+
@Operation(summary = "summary2")
24+
@QuerySort
25+
@QueryPaging
26+
public List<?> list2(String page, String size, String sort) {return null; }
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package test.org.springdoc.api.app60;
2+
3+
import io.swagger.v3.oas.annotations.Parameter;
4+
import io.swagger.v3.oas.annotations.Parameters;
5+
6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
10+
11+
@Retention(RetentionPolicy.RUNTIME)
12+
@Target({ ElementType.METHOD })
13+
@Parameters({
14+
@Parameter(name = "page", description = "desc page from Annotated interface"),
15+
@Parameter(name = "size", description = "desc page from Annotated interface")
16+
})
17+
public @interface QueryPaging {
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package test.org.springdoc.api.app60;
2+
3+
import io.swagger.v3.oas.annotations.Parameter;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
@Retention(RetentionPolicy.RUNTIME)
11+
@Target({ElementType.METHOD})
12+
@Parameter(name = "sort", description = "desc sort from Annotated interface")
13+
public @interface QuerySort {
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package test.org.springdoc.api.app60;
2+
3+
import test.org.springdoc.api.AbstractSpringDocTest;
4+
5+
public class SpringDocApp60Test extends AbstractSpringDocTest {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package test.org.springdoc.api.app60;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class SpringDocTestApp {
8+
public static void main(String[] args) {
9+
SpringApplication.run(SpringDocTestApp.class, args);
10+
}
11+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
{
2+
"components": {},
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"openapi": "3.0.1",
8+
"paths": {
9+
"/hello1": {
10+
"get": {
11+
"operationId": "list1",
12+
"parameters": [
13+
{
14+
"description": "The page",
15+
"in": "query",
16+
"name": "page",
17+
"required": true,
18+
"schema": {
19+
"type": "string"
20+
}
21+
},
22+
{
23+
"description": "The size",
24+
"in": "query",
25+
"name": "size",
26+
"required": true,
27+
"schema": {
28+
"type": "string"
29+
}
30+
}
31+
],
32+
"responses": {
33+
"200": {
34+
"content": {
35+
"*/*": {
36+
"schema": {
37+
"items": {
38+
"type": "object"
39+
},
40+
"type": "array"
41+
}
42+
}
43+
},
44+
"description": "default response"
45+
}
46+
},
47+
"summary": "summary1",
48+
"tags": [
49+
"hello-controller"
50+
]
51+
}
52+
},
53+
"/hello2": {
54+
"get": {
55+
"operationId": "list2",
56+
"parameters": [
57+
{
58+
"description": "desc page from Annotated interface",
59+
"in": "query",
60+
"name": "page",
61+
"required": true,
62+
"schema": {
63+
"type": "string"
64+
}
65+
},
66+
{
67+
"description": "desc page from Annotated interface",
68+
"in": "query",
69+
"name": "size",
70+
"required": true,
71+
"schema": {
72+
"type": "string"
73+
}
74+
},
75+
{
76+
"description": "desc sort from Annotated interface",
77+
"in": "query",
78+
"name": "sort",
79+
"required": true,
80+
"schema": {
81+
"type": "string"
82+
}
83+
}
84+
],
85+
"responses": {
86+
"200": {
87+
"content": {
88+
"*/*": {
89+
"schema": {
90+
"items": {
91+
"type": "object"
92+
},
93+
"type": "array"
94+
}
95+
}
96+
},
97+
"description": "default response"
98+
}
99+
},
100+
"summary": "summary2",
101+
"tags": [
102+
"hello-controller"
103+
]
104+
}
105+
}
106+
},
107+
"servers": [
108+
{
109+
"description": "Generated server url",
110+
"url": "http://localhost"
111+
}
112+
]
113+
}

0 commit comments

Comments
 (0)