Skip to content

Commit 514a774

Browse files
author
bnasslahsen
committed
Add support for @ParameterObject with POST endpoints. Fixes #693
1 parent 44f1e16 commit 514a774

File tree

9 files changed

+407
-13
lines changed

9 files changed

+407
-13
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- #674 - Support @Parameter annotation attached to @RequestPart, for several @RequestParts
1212
- #658 - Added support for GroupedOpenApi OperationCustomizer
1313
- #654 - Use oneOf schema for polymorphic types
14-
- Separate module for spring-hateoas
14+
- #693 - Add support for @ParameterObject with POST endpoints
15+
- Added separate module for spring-hateoas
1516
- Added SpringDocUtils.addHiddenRestControllers(String ...)
1617

1718
### Changed

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public abstract class AbstractRequestBuilder {
127127
private final Optional<List<ParameterCustomizer>> parameterCustomizers;
128128

129129
protected AbstractRequestBuilder(GenericParameterBuilder parameterBuilder, RequestBodyBuilder requestBodyBuilder,
130-
OperationBuilder operationBuilder,Optional<List<ParameterCustomizer>> parameterCustomizers,
130+
OperationBuilder operationBuilder, Optional<List<ParameterCustomizer>> parameterCustomizers,
131131
LocalVariableTableParameterNameDiscoverer localSpringDocParameterNameDiscoverer) {
132132
super();
133133
this.parameterBuilder = parameterBuilder;
@@ -285,34 +285,36 @@ public Parameter buildParams(ParameterInfo parameterInfo, Components components,
285285
PathVariable pathVar = parameterInfo.getPathVar();
286286
CookieValue cookieValue = parameterInfo.getCookieValue();
287287

288-
Parameter parameter = null;
289288
RequestInfo requestInfo;
290289

291290
if (requestHeader != null) {
292291
requestInfo = new RequestInfo(ParameterIn.HEADER.toString(), parameterInfo.getpName(), requestHeader.required(),
293292
requestHeader.defaultValue());
294-
parameter = buildParam(parameterInfo, components, requestInfo, jsonView);
293+
return buildParam(parameterInfo, components, requestInfo, jsonView);
295294

296295
}
297296
else if (requestParam != null && !parameterBuilder.isFile(parameterInfo.getMethodParameter())) {
298297
requestInfo = new RequestInfo(ParameterIn.QUERY.toString(), parameterInfo.getpName(), requestParam.required() && !methodParameter.isOptional(),
299298
requestParam.defaultValue());
300-
parameter = buildParam(parameterInfo, components, requestInfo, jsonView);
299+
return buildParam(parameterInfo, components, requestInfo, jsonView);
301300
}
302301
else if (pathVar != null) {
303302
requestInfo = new RequestInfo(ParameterIn.PATH.toString(), parameterInfo.getpName(), !methodParameter.isOptional(), null);
304-
parameter = buildParam(parameterInfo, components, requestInfo, jsonView);
303+
return buildParam(parameterInfo, components, requestInfo, jsonView);
305304
}
306305
else if (cookieValue != null) {
307306
requestInfo = new RequestInfo(ParameterIn.COOKIE.toString(), parameterInfo.getpName(), cookieValue.required(),
308307
cookieValue.defaultValue());
309-
parameter = buildParam(parameterInfo, components, requestInfo, jsonView);
308+
return buildParam(parameterInfo, components, requestInfo, jsonView);
310309
}
311310
// By default
312-
if (RequestMethod.GET.equals(requestMethod) || (parameterInfo.getParameterModel() != null && ParameterIn.PATH.toString().equals(parameterInfo.getParameterModel().getIn())))
313-
parameter = this.buildParam(QUERY_PARAM, components, parameterInfo, !methodParameter.isOptional(), null, jsonView);
311+
DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
312+
if (RequestMethod.GET.equals(requestMethod)
313+
|| (parameterInfo.getParameterModel() != null && (ParameterIn.PATH.toString().equals(parameterInfo.getParameterModel().getIn())))
314+
|| delegatingMethodParameter.isParameterObject())
315+
return this.buildParam(QUERY_PARAM, components, parameterInfo, !methodParameter.isOptional(), null, jsonView);
314316

315-
return parameter;
317+
return null;
316318
}
317319

318320
private Parameter buildParam(ParameterInfo parameterInfo, Components components, RequestInfo requestInfo,

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,14 @@ public class DelegatingMethodParameter extends MethodParameter {
5151

5252
private String parameterName;
5353

54-
DelegatingMethodParameter(MethodParameter delegate, String parameterName, Annotation[] additionalParameterAnnotations) {
54+
private boolean isParameterObject;
55+
56+
DelegatingMethodParameter(MethodParameter delegate, String parameterName, Annotation[] additionalParameterAnnotations, boolean isParameterObject) {
5557
super(delegate);
5658
this.delegate = delegate;
5759
this.additionalParameterAnnotations = additionalParameterAnnotations;
5860
this.parameterName = parameterName;
61+
this.isParameterObject=isParameterObject;
5962
}
6063

6164
public static MethodParameter[] customize(String[] pNames, MethodParameter[] parameters) {
@@ -68,7 +71,7 @@ public static MethodParameter[] customize(String[] pNames, MethodParameter[] par
6871
}
6972
else {
7073
String name = pNames != null ? pNames[i] : p.getParameterName();
71-
explodedParameters.add(new DelegatingMethodParameter(p, name, null));
74+
explodedParameters.add(new DelegatingMethodParameter(p, name, null,false));
7275
}
7376
}
7477
return explodedParameters.toArray(new MethodParameter[0]);
@@ -167,4 +170,8 @@ public int hashCode() {
167170
result = 31 * result + Arrays.hashCode(additionalParameterAnnotations);
168171
return result;
169172
}
173+
174+
public boolean isParameterObject() {
175+
return isParameterObject;
176+
}
170177
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private static Stream<MethodParameter> fromSimpleClass(Class<?> paramClass, Fiel
101101
.map(PropertyDescriptor::getReadMethod)
102102
.filter(Objects::nonNull)
103103
.map(method -> new MethodParameter(method, -1))
104-
.map(param -> new DelegatingMethodParameter(param, fieldNamePrefix + field.getName(), finalFieldAnnotations));
104+
.map(param -> new DelegatingMethodParameter(param, fieldNamePrefix + field.getName(), finalFieldAnnotations, true));
105105
}
106106
catch (IntrospectionException e) {
107107
return Stream.of();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package test.org.springdoc.api.app121;
2+
3+
import javax.validation.constraints.NotBlank;
4+
5+
import io.swagger.v3.oas.annotations.Parameter;
6+
7+
public class InheritedRequestParams extends RequestParams {
8+
9+
@Parameter(description = "parameter from child of RequestParams")
10+
@NotBlank
11+
private String childParam;
12+
13+
public String getChildParam() {
14+
return childParam;
15+
}
16+
17+
public void setChildParam(String childParam) {
18+
this.childParam = childParam;
19+
}
20+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package test.org.springdoc.api.app121;
2+
3+
import java.math.BigInteger;
4+
import java.util.List;
5+
import java.util.Optional;
6+
7+
import com.sun.istack.internal.Nullable;
8+
import io.swagger.v3.oas.annotations.Parameter;
9+
10+
11+
public class RequestParams {
12+
13+
@Parameter(description = "string parameter")
14+
private String stringParam;
15+
16+
@Deprecated
17+
private String stringParam1;
18+
19+
@Parameter(description = "string parameter2", required = true)
20+
private String stringParam2;
21+
22+
@Parameter(description = "int parameter")
23+
private int intParam;
24+
25+
private Optional<String> intParam2;
26+
27+
private String intParam3;
28+
29+
private Nested nested;
30+
31+
private List<Nested> nestedList;
32+
33+
public String getStringParam() {
34+
return stringParam;
35+
}
36+
37+
public void setStringParam(String stringParam) {
38+
this.stringParam = stringParam;
39+
}
40+
41+
public int getIntParam() {
42+
return intParam;
43+
}
44+
45+
public void setIntParam(int intParam) {
46+
this.intParam = intParam;
47+
}
48+
49+
public Optional<String> getIntParam2() {
50+
return intParam2;
51+
}
52+
53+
public void setIntParam2(Optional<String> intParam2) {
54+
this.intParam2 = intParam2;
55+
}
56+
57+
@Nullable
58+
public String getIntParam3() {
59+
return intParam3;
60+
}
61+
62+
public void setIntParam3(@Nullable String intParam3) {
63+
this.intParam3 = intParam3;
64+
}
65+
66+
public String getStringParam1() {
67+
return stringParam1;
68+
}
69+
70+
public void setStringParam1(String stringParam1) {
71+
this.stringParam1 = stringParam1;
72+
}
73+
74+
public String getStringParam2() {
75+
return stringParam2;
76+
}
77+
78+
public void setStringParam2(String stringParam2) {
79+
this.stringParam2 = stringParam2;
80+
}
81+
82+
public Nested getNested() {
83+
return nested;
84+
}
85+
86+
public void setNested(Nested nested) {
87+
this.nested = nested;
88+
}
89+
90+
public List<Nested> getNestedList() {
91+
return nestedList;
92+
}
93+
94+
public void setNestedList(List<Nested> nestedList) {
95+
this.nestedList = nestedList;
96+
}
97+
98+
public static class Nested {
99+
private String param1;
100+
101+
private BigInteger param2;
102+
103+
@Parameter(description = "nested string parameter")
104+
public String getParam1() {
105+
return param1;
106+
}
107+
108+
public void setParam1(String param1) {
109+
this.param1 = param1;
110+
}
111+
112+
@Parameter(description = "nested BigInteger parameter")
113+
public BigInteger getParam2() {
114+
return param2;
115+
}
116+
117+
public void setParam2(BigInteger param2) {
118+
this.param2 = param2;
119+
}
120+
}
121+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * * Copyright 2019-2020 the original author or authors.
6+
* * * *
7+
* * * * Licensed under the Apache License, Version 2.0 (the "License");
8+
* * * * you may not use this file except in compliance with the License.
9+
* * * * You may obtain a copy of the License at
10+
* * * *
11+
* * * * https://www.apache.org/licenses/LICENSE-2.0
12+
* * * *
13+
* * * * Unless required by applicable law or agreed to in writing, software
14+
* * * * distributed under the License is distributed on an "AS IS" BASIS,
15+
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* * * * See the License for the specific language governing permissions and
17+
* * * * limitations under the License.
18+
* * *
19+
* *
20+
*
21+
*
22+
*/
23+
package test.org.springdoc.api.app121;
24+
25+
import test.org.springdoc.api.AbstractSpringDocTest;
26+
27+
import org.springframework.boot.autoconfigure.SpringBootApplication;
28+
29+
30+
/**
31+
* Tests Spring meta-annotations as method parameters
32+
*/
33+
public class SpringDocApp121Test extends AbstractSpringDocTest {
34+
35+
@SpringBootApplication
36+
static class SpringDocTestApp {}
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package test.org.springdoc.api.app121;
2+
3+
import com.sun.istack.internal.Nullable;
4+
import org.springdoc.api.annotations.ParameterObject;
5+
6+
import org.springframework.web.bind.annotation.PostMapping;
7+
import org.springframework.web.bind.annotation.RequestParam;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
@RestController
11+
public class TestController {
12+
13+
@PostMapping("test")
14+
public InheritedRequestParams getTest(@RequestParam @Nullable String param, @ParameterObject InheritedRequestParams requestParams) {
15+
return requestParams;
16+
}
17+
}

0 commit comments

Comments
 (0)