Skip to content

Commit ab424eb

Browse files
committed
Enhance RequestBody Management - Fixes #1142
1 parent 94ac7ed commit ab424eb

File tree

11 files changed

+188
-57
lines changed

11 files changed

+188
-57
lines changed

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

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
import io.swagger.v3.oas.models.media.StringSchema;
5656
import io.swagger.v3.oas.models.parameters.Parameter;
5757
import io.swagger.v3.oas.models.parameters.RequestBody;
58+
import org.apache.commons.lang3.ArrayUtils;
59+
import org.apache.commons.lang3.ClassUtils;
5860
import org.apache.commons.lang3.StringUtils;
5961
import org.springdoc.core.customizers.ParameterCustomizer;
6062

@@ -96,7 +98,7 @@ public abstract class AbstractRequestService {
9698
* The constant ANNOTATIONS_FOR_REQUIRED.
9799
*/
98100
// using string litterals to support both validation-api v1 and v2
99-
private static final String[] ANNOTATIONS_FOR_REQUIRED = {"NotNull", "NonNull", "NotBlank", "NotEmpty"};
101+
private static final String[] ANNOTATIONS_FOR_REQUIRED = { "NotNull", "NonNull", "NotBlank", "NotEmpty" };
100102

101103
/**
102104
* The constant POSITIVE_OR_ZERO.
@@ -255,7 +257,7 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
255257
}
256258

257259
if (!isParamToIgnore(methodParameter)) {
258-
parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes.getJsonViewAnnotation());
260+
parameter = buildParams(parameterInfo, parameters.length, components, requestMethod, methodAttributes.getJsonViewAnnotation());
259261
// Merge with the operation parameters
260262
parameter = GenericParameterService.mergeParameter(operationParameters, parameter);
261263
List<Annotation> parameterAnnotations = Arrays.asList(methodParameter.getParameterAnnotations());
@@ -321,7 +323,7 @@ private LinkedHashMap<String, Parameter> getParameterLinkedHashMap(Components co
321323
public static Collection<Parameter> getHeaders(MethodAttributes methodAttributes, Map<String, Parameter> map) {
322324
for (Map.Entry<String, String> entry : methodAttributes.getHeaders().entrySet()) {
323325
StringSchema schema = new StringSchema();
324-
if(StringUtils.isNotEmpty(entry.getValue()))
326+
if (StringUtils.isNotEmpty(entry.getValue()))
325327
schema.addEnumItem(entry.getValue());
326328
Parameter parameter = new Parameter().in(ParameterIn.HEADER.toString()).name(entry.getKey()).schema(schema);
327329
if (map.containsKey(entry.getKey())) {
@@ -404,26 +406,24 @@ public boolean isValidParameter(Parameter parameter) {
404406
* Build params parameter.
405407
*
406408
* @param parameterInfo the parameter info
409+
* @param length the length
407410
* @param components the components
408411
* @param requestMethod the request method
409412
* @param jsonView the json view
410413
* @return the parameter
411414
*/
412-
public Parameter buildParams(ParameterInfo parameterInfo, Components components,
415+
public Parameter buildParams(ParameterInfo parameterInfo, int length, Components components,
413416
RequestMethod requestMethod, JsonView jsonView) {
414417
MethodParameter methodParameter = parameterInfo.getMethodParameter();
415-
if (parameterInfo.getParamType() != null){
418+
if (parameterInfo.getParamType() != null) {
416419
if (!ValueConstants.DEFAULT_NONE.equals(parameterInfo.getDefaultValue()))
417420
parameterInfo.setRequired(false);
418421
else
419422
parameterInfo.setDefaultValue(null);
420423
return this.buildParam(parameterInfo, components, jsonView);
421424
}
422425
// By default
423-
DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
424-
if (RequestMethod.GET.equals(requestMethod)
425-
|| (parameterInfo.getParameterModel() != null && parameterInfo.getParameterModel().getIn() !=null)
426-
|| delegatingMethodParameter.isParameterObject()){
426+
if (!isRequestBodyParam(requestMethod, parameterInfo, length)) {
427427
parameterInfo.setRequired(!methodParameter.isOptional());
428428
parameterInfo.setParamType(QUERY_PARAM);
429429
parameterInfo.setDefaultValue(null);
@@ -440,7 +440,7 @@ public Parameter buildParams(ParameterInfo parameterInfo, Components components,
440440
* @param jsonView the json view
441441
* @return the parameter
442442
*/
443-
private Parameter buildParam(ParameterInfo parameterInfo, Components components, JsonView jsonView) {
443+
public Parameter buildParam(ParameterInfo parameterInfo, Components components, JsonView jsonView) {
444444
Parameter parameter = parameterInfo.getParameterModel();
445445
String name = parameterInfo.getpName();
446446

@@ -632,4 +632,23 @@ private void applyValidationsToSchema(Map<String, Annotation> annos, Schema<?> s
632632
}
633633
}
634634

635+
/**
636+
* Is RequestBody param boolean.
637+
*
638+
* @param requestMethod the request method
639+
* @param parameterInfo the parameter info
640+
* @param length the length
641+
* @return the boolean
642+
*/
643+
private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo parameterInfo, int length) {
644+
MethodParameter methodParameter = parameterInfo.getMethodParameter();
645+
DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
646+
647+
return (!RequestMethod.GET.equals(requestMethod) && (parameterInfo.getParameterModel() == null || parameterInfo.getParameterModel().getIn() == null) && !delegatingMethodParameter.isParameterObject())
648+
&&
649+
((methodParameter.getParameterAnnotation(io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null
650+
|| methodParameter.getParameterAnnotation(org.springframework.web.bind.annotation.RequestBody.class) != null)
651+
|| (!ClassUtils.isPrimitiveOrWrapper(methodParameter.getParameter().getType()) && (!ArrayUtils.isEmpty(methodParameter.getParameterAnnotations()) || length == 1)));
652+
}
653+
635654
}

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestRequestService.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public DataRestRequestService(LocalVariableTableParameterNameDiscoverer localSpr
121121
* @param resourceMetadata the resource metadata
122122
* @param dataRestRepository the data rest repository
123123
*/
124-
public void buildParameters( OpenAPI openAPI, HandlerMethod handlerMethod, RequestMethod requestMethod, MethodAttributes methodAttributes,
124+
public void buildParameters(OpenAPI openAPI, HandlerMethod handlerMethod, RequestMethod requestMethod, MethodAttributes methodAttributes,
125125
Operation operation, ResourceMetadata resourceMetadata, DataRestRepository dataRestRepository) {
126126
String[] pNames = this.localSpringDocParameterNameDiscoverer.getParameterNames(handlerMethod.getMethod());
127127
MethodParameter[] parameters = handlerMethod.getMethodParameters();
@@ -133,7 +133,7 @@ public void buildParameters( OpenAPI openAPI, HandlerMethod handlerMethod, Reque
133133
String[] reflectionParametersNames = Arrays.stream(handlerMethod.getMethod().getParameters()).map(java.lang.reflect.Parameter::getName).toArray(String[]::new);
134134
if (pNames == null || Arrays.stream(pNames).anyMatch(Objects::isNull))
135135
pNames = reflectionParametersNames;
136-
buildCommonParameters(openAPI, requestMethod, methodAttributes, operation, pNames, parameters, resourceMetadata,dataRestRepository);
136+
buildCommonParameters(openAPI, requestMethod, methodAttributes, operation, pNames, parameters, resourceMetadata, dataRestRepository);
137137
}
138138

139139
/**
@@ -163,7 +163,7 @@ public void buildCommonParameters(OpenAPI openAPI, RequestMethod requestMethod,
163163
else if (methodParameter.getParameterAnnotation(BackendId.class) != null) {
164164
parameterInfo.setParameterModel(new Parameter().name("id").in(ParameterIn.PATH.toString()).schema(new StringSchema()));
165165
}
166-
Parameter parameter;
166+
Parameter parameter = null;
167167
io.swagger.v3.oas.annotations.Parameter parameterDoc = AnnotatedElementUtils.findMergedAnnotation(
168168
AnnotatedElementUtils.forAnnotations(methodParameter.getParameterAnnotations()),
169169
io.swagger.v3.oas.annotations.Parameter.class);
@@ -173,7 +173,8 @@ else if (methodParameter.getParameterAnnotation(BackendId.class) != null) {
173173
parameter = parameterBuilder.buildParameterFromDoc(parameterDoc, openAPI.getComponents(), methodAttributes.getJsonViewAnnotation());
174174
parameterInfo.setParameterModel(parameter);
175175
}
176-
parameter = requestBuilder.buildParams(parameterInfo, openAPI.getComponents(), requestMethod, null);
176+
if (!ArrayUtils.isEmpty(methodParameter.getParameterAnnotations()))
177+
parameter = requestBuilder.buildParams(parameterInfo, parameters.length, openAPI.getComponents(), requestMethod, null);
177178

178179
addParameters(openAPI, requestMethod, methodAttributes, operation, methodParameter, parameterInfo, parameter);
179180
}

springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app69/UserHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public Mono<ServerResponse> getAll(ServerRequest request) {
3535
*/
3636
public Mono<ServerResponse> getUser(ServerRequest request) {
3737
// parse path-variable
38-
long customerId = Long.valueOf(request.pathVariable("id"));
38+
long customerId = Long.valueOf(request.queryParam("id").get());
3939

4040
// build notFound response
4141
Mono<ServerResponse> notFound = ServerResponse.notFound().build();

springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app69/UserRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.swagger.v3.oas.annotations.Operation;
44
import io.swagger.v3.oas.annotations.Parameter;
55
import io.swagger.v3.oas.annotations.enums.ParameterIn;
6+
import io.swagger.v3.oas.annotations.parameters.RequestBody;
67
import reactor.core.publisher.Flux;
78
import reactor.core.publisher.Mono;
89

@@ -18,7 +19,7 @@ public interface UserRepository {
1819

1920
public Mono<Void> saveUser(Mono<User> user);
2021

21-
public Mono<User> putUser(@Parameter(in = ParameterIn.PATH) Long id, Mono<User> user);
22+
public Mono<User> putUser(@Parameter(in = ParameterIn.PATH) Long id, @RequestBody Mono<User> user);
2223

2324
public Mono<String> deleteUser(@Parameter(in = ParameterIn.PATH) Long id);
2425
}

springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app82/UserHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public Mono<ServerResponse> getAll(ServerRequest request) {
3535
*/
3636
public Mono<ServerResponse> getUser(ServerRequest request) {
3737
// parse path-variable
38-
long customerId = Long.valueOf(request.pathVariable("id"));
38+
long customerId = Long.valueOf(request.queryParam("id").get());
3939

4040
// build notFound response
4141
Mono<ServerResponse> notFound = ServerResponse.notFound().build();

springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app82/UserRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.swagger.v3.oas.annotations.Operation;
44
import io.swagger.v3.oas.annotations.Parameter;
55
import io.swagger.v3.oas.annotations.enums.ParameterIn;
6+
import io.swagger.v3.oas.annotations.parameters.RequestBody;
67
import reactor.core.publisher.Flux;
78
import reactor.core.publisher.Mono;
89

@@ -18,7 +19,7 @@ public interface UserRepository {
1819

1920
public Mono<Void> saveUser(Mono<User> user);
2021

21-
public Mono<User> putUser(@Parameter(in = ParameterIn.QUERY) Long id, Mono<User> user);
22+
public Mono<User> putUser(@Parameter(in = ParameterIn.QUERY) Long id, @RequestBody Mono<User> user);
2223

2324
public Mono<String> deleteUser(@Parameter(in = ParameterIn.PATH) Long id);
2425
}

springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app129/HelloController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import io.swagger.v3.oas.annotations.responses.ApiResponse;
2222
import io.swagger.v3.oas.annotations.responses.ApiResponses;
2323

24-
import org.springframework.web.bind.annotation.GetMapping;
24+
import org.springframework.web.bind.annotation.PostMapping;
2525
import org.springframework.web.bind.annotation.RequestBody;
2626
import org.springframework.web.bind.annotation.RequestMapping;
2727
import org.springframework.web.bind.annotation.RestController;
@@ -31,7 +31,7 @@
3131
@RequestMapping(path = "/api", headers = {"userId", "registrationId"})
3232
public class HelloController {
3333

34-
@GetMapping("/test")
34+
@PostMapping("/test")
3535
@ApiResponses({@ApiResponse(responseCode = "200")})
3636
public DeferredResult<OperationResponse<ActualReturnedEntity>> update(
3737
@RequestBody ActualReturnedEntity entity) throws Exception {

springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app154/HelloController.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
@RestController
3131
public class HelloController {
3232

33+
3334
@GetMapping(path = "/")
3435
public String hello() {
3536
return "Hello world at " + Instant.now().toString();
@@ -39,4 +40,20 @@ public String hello() {
3940
public void create(@ParameterObject Long id, @RequestBody Object o){
4041

4142
}
43+
44+
@PostMapping(value = "/personsone")
45+
public void createone(Long id, @RequestBody Object o){
46+
47+
}
48+
49+
@PostMapping(value = "/createtwo")
50+
public void createtwo(int id){
51+
52+
}
53+
54+
@PostMapping(value = "/createthree")
55+
public void createthree(Integer id){
56+
57+
}
58+
4259
}

springdoc-openapi-webmvc-core/src/test/resources/results/app129.json

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,12 @@
1212
],
1313
"paths": {
1414
"/api/test": {
15-
"get": {
15+
"post": {
1616
"tags": [
1717
"hello-controller"
1818
],
1919
"operationId": "update",
2020
"parameters": [
21-
{
22-
"name": "entity",
23-
"in": "query",
24-
"required": true,
25-
"schema": {
26-
"$ref": "#/components/schemas/ActualReturnedEntity"
27-
}
28-
},
2921
{
3022
"name": "userId",
3123
"in": "header",
@@ -41,6 +33,16 @@
4133
}
4234
}
4335
],
36+
"requestBody": {
37+
"content": {
38+
"application/json": {
39+
"schema": {
40+
"$ref": "#/components/schemas/ActualReturnedEntity"
41+
}
42+
}
43+
},
44+
"required": true
45+
},
4446
"responses": {
4547
"200": {
4648
"description": "OK",

0 commit comments

Comments
 (0)