1 /*
2  *
3  *  * Copyright 2019-2020 the original author or authors.
4  *  *
5  *  * Licensed under the Apache License, Version 2.0 (the "License");
6  *  * you may not use this file except in compliance with the License.
7  *  * You may obtain a copy of the License at
8  *  *
9  *  *      https://www.apache.org/licenses/LICENSE-2.0
10  *  *
11  *  * Unless required by applicable law or agreed to in writing, software
12  *  * distributed under the License is distributed on an "AS IS" BASIS,
13  *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  * See the License for the specific language governing permissions and
15  *  * limitations under the License.
16  *
17  */

18
19 package org.springdoc.core;
20
21 import java.util.Map;
22 import java.util.Optional;
23
24 import com.fasterxml.jackson.annotation.JsonView;
25 import io.swagger.v3.core.util.AnnotationsUtils;
26 import io.swagger.v3.oas.models.Components;
27 import io.swagger.v3.oas.models.media.Content;
28 import io.swagger.v3.oas.models.media.Schema;
29 import io.swagger.v3.oas.models.parameters.RequestBody;
30 import org.apache.commons.lang3.StringUtils;
31
32 import org.springframework.core.MethodParameter;
33 import org.springframework.web.bind.annotation.RequestPart;
34
35 public class RequestBodyBuilder {
36
37     private final GenericParameterBuilder parameterBuilder;
38
39     public RequestBodyBuilder(GenericParameterBuilder parameterBuilder) {
40         super();
41         this.parameterBuilder = parameterBuilder;
42     }
43
44     public Optional<RequestBody> buildRequestBodyFromDoc(
45             io.swagger.v3.oas.annotations.parameters.RequestBody requestBody, String[] classConsumes,
46             String[] methodConsumes, Components components, JsonView jsonViewAnnotation) {
47         if (requestBody == null)
48             return Optional.empty();
49         RequestBody requestBodyObject = new RequestBody();
50         boolean isEmpty = true;
51
52         if (StringUtils.isNotBlank(requestBody.ref())) {
53             requestBodyObject.set$ref(requestBody.ref());
54             return Optional.of(requestBodyObject);
55         }
56
57         if (StringUtils.isNotBlank(requestBody.description())) {
58             requestBodyObject.setDescription(requestBody.description());
59             isEmpty = false;
60         }
61
62         if (requestBody.required()) {
63             requestBodyObject.setRequired(requestBody.required());
64             isEmpty = false;
65         }
66         if (requestBody.extensions().length > 0) {
67             Map<String, Object> extensions = AnnotationsUtils.getExtensions(requestBody.extensions());
68             extensions.forEach(requestBodyObject::addExtension);
69             isEmpty = false;
70         }
71
72         if (requestBody.content().length > 0)
73             isEmpty = false;
74
75         if (isEmpty)
76             return Optional.empty();
77
78         AnnotationsUtils
79                 .getContent(requestBody.content(), classConsumes == null ? new String[0] : classConsumes,
80                         methodConsumes == null ? new String[0] : methodConsumes, null, components, jsonViewAnnotation)
81                 .ifPresent(requestBodyObject::setContent);
82         return Optional.of(requestBodyObject);
83     }
84
85     public void calculateRequestBodyInfo(Components components, MethodAttributes methodAttributes,
86             ParameterInfo parameterInfo, RequestBodyInfo requestBodyInfo) {
87         RequestBody requestBody = requestBodyInfo.getRequestBody();
88         MethodParameter methodParameter = parameterInfo.getMethodParameter();
89         // Get it from parameter level, if not present
90         if (requestBody == null) {
91             io.swagger.v3.oas.annotations.parameters.RequestBody requestBodyDoc = methodParameter.getParameterAnnotation(io.swagger.v3.oas.annotations.parameters.RequestBody.class);
92             requestBody = this.buildRequestBodyFromDoc(requestBodyDoc, methodAttributes.getClassConsumes(),
93                     methodAttributes.getMethodConsumes(), components, null).orElse(null);
94         }
95
96         RequestPart requestPart = methodParameter.getParameterAnnotation(RequestPart.class);
97         String paramName = null;
98         if (requestPart != null)
99             paramName = StringUtils.defaultIfEmpty(requestPart.value(), requestPart.name());
100         paramName = StringUtils.defaultIfEmpty(paramName, parameterInfo.getpName());
101         parameterInfo.setpName(paramName);
102
103         requestBody = buildRequestBody(requestBody, components, methodAttributes, parameterInfo,
104                 requestBodyInfo);
105         requestBodyInfo.setRequestBody(requestBody);
106     }
107
108     private RequestBody buildRequestBody(RequestBody requestBody, Components components,
109             MethodAttributes methodAttributes,
110             ParameterInfo parameterInfo, RequestBodyInfo requestBodyInfo) {
111         if (requestBody == null)
112             requestBody = new RequestBody();
113
114         if (parameterInfo.getParameterModel() != null) {
115             io.swagger.v3.oas.models.parameters.Parameter parameter = parameterInfo.getParameterModel();
116             if (StringUtils.isNotBlank(parameter.getDescription()))
117                 requestBody.setDescription(parameter.getDescription());
118             requestBody.setRequired(parameter.getRequired());
119         }
120
121         if (requestBody.getContent() == null) {
122             Schema<?> schema = parameterBuilder.calculateSchema(components, parameterInfo, requestBodyInfo,
123                     methodAttributes.getJsonViewAnnotationForRequestBody());
124             buildContent(requestBody, methodAttributes, schema);
125         }
126         else if (requestBodyInfo.getRequestBody() != null) {
127             Schema<?> schema = parameterBuilder.calculateSchema(components, parameterInfo, requestBodyInfo,
128                     methodAttributes.getJsonViewAnnotationForRequestBody());
129             mergeContent(requestBody, methodAttributes, schema);
130         }
131         return requestBody;
132     }
133
134     private void mergeContent(RequestBody requestBody, MethodAttributes methodAttributes, Schema<?> schema) {
135         Content content = requestBody.getContent();
136         buildContent(requestBody, methodAttributes, schema, content);
137     }
138
139     private void buildContent(RequestBody requestBody, MethodAttributes methodAttributes, Schema<?> schema) {
140         Content content = new Content();
141         buildContent(requestBody, methodAttributes, schema, content);
142     }
143
144     private void buildContent(RequestBody requestBody, MethodAttributes methodAttributes, Schema<?> schema, Content content) {
145         for (String value : methodAttributes.getMethodConsumes()) {
146             io.swagger.v3.oas.models.media.MediaType mediaTypeObject = new io.swagger.v3.oas.models.media.MediaType();
147             mediaTypeObject.setSchema(schema);
148             if (content.get(value) != null) {
149                 mediaTypeObject.setExample(content.get(value).getExample());
150                 mediaTypeObject.setExamples(content.get(value).getExamples());
151                 mediaTypeObject.setEncoding(content.get(value).getEncoding());
152             }
153             content.addMediaType(value, mediaTypeObject);
154         }
155         requestBody.setContent(content);
156     }
157 }
158