Skip to content

Commit 4ce8b18

Browse files
author
bnasslahsen
committed
initial version for #1744
1 parent d3d5e57 commit 4ce8b18

File tree

7 files changed

+315
-130
lines changed

7 files changed

+315
-130
lines changed

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

Lines changed: 149 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@
4949

5050
import com.fasterxml.jackson.annotation.JsonView;
5151
import io.swagger.v3.core.util.PrimitiveType;
52+
import io.swagger.v3.oas.annotations.enums.Explode;
5253
import io.swagger.v3.oas.annotations.enums.ParameterIn;
54+
import io.swagger.v3.oas.annotations.enums.ParameterStyle;
55+
import io.swagger.v3.oas.annotations.extensions.Extension;
56+
import io.swagger.v3.oas.annotations.media.ArraySchema;
57+
import io.swagger.v3.oas.annotations.media.ExampleObject;
5358
import io.swagger.v3.oas.models.Components;
5459
import io.swagger.v3.oas.models.OpenAPI;
5560
import io.swagger.v3.oas.models.Operation;
@@ -237,10 +242,13 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
237242
String[] reflectionParametersNames = Arrays.stream(handlerMethod.getMethod().getParameters()).map(java.lang.reflect.Parameter::getName).toArray(String[]::new);
238243
if (pNames == null || Arrays.stream(pNames).anyMatch(Objects::isNull))
239244
pNames = reflectionParametersNames;
240-
parameters = DelegatingMethodParameter.customize(pNames, parameters, parameterBuilder.getDelegatingMethodParameterCustomizer());
245+
parameters = DelegatingMethodParameter.customize(pNames, parameters,
246+
parameterBuilder.getDelegatingMethodParameterCustomizer(),requestMethod);
241247
RequestBodyInfo requestBodyInfo = new RequestBodyInfo();
242-
List<Parameter> operationParameters = (operation.getParameters() != null) ? operation.getParameters() : new ArrayList<>();
243-
Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(handlerMethod.getMethod());
248+
List<Parameter> operationParameters = (operation.getParameters() != null) ? operation.getParameters()
249+
: new ArrayList<>();
250+
Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(
251+
handlerMethod.getMethod());
244252
Components components = openAPI.getComponents();
245253

246254
JavadocProvider javadocProvider = operationService.getJavadocProvider();
@@ -255,19 +263,32 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
255263
final String pName = methodParameter.getParameterName();
256264
ParameterInfo parameterInfo = new ParameterInfo(pName, methodParameter, parameterBuilder);
257265

258-
if (parameterDoc == null)
266+
if (parameterDoc == null) {
259267
parameterDoc = parametersDocMap.get(parameterInfo.getpName());
268+
}
269+
// TODO Use Schema
270+
if (parameterDoc == null) {
271+
io.swagger.v3.oas.annotations.media.Schema schema = AnnotatedElementUtils.findMergedAnnotation(
272+
AnnotatedElementUtils.forAnnotations(methodParameter.getParameterAnnotations()), io.swagger.v3.oas.annotations.media.Schema.class);
273+
if (schema != null) {
274+
parameterDoc = generateParameterBySchema(schema);
275+
}
276+
}
277+
// TODO Use Schema End
260278
// use documentation as reference
261279
if (parameterDoc != null) {
262-
if (parameterDoc.hidden() || parameterDoc.schema().hidden())
280+
if (parameterDoc.hidden() || parameterDoc.schema().hidden()) {
263281
continue;
282+
}
264283

265-
parameter = parameterBuilder.buildParameterFromDoc(parameterDoc, components, methodAttributes.getJsonViewAnnotation(), methodAttributes.getLocale());
284+
parameter = parameterBuilder.buildParameterFromDoc(parameterDoc, components,
285+
methodAttributes.getJsonViewAnnotation(), methodAttributes.getLocale());
266286
parameterInfo.setParameterModel(parameter);
267287
}
268288

269289
if (!isParamToIgnore(methodParameter)) {
270-
parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes.getJsonViewAnnotation());
290+
parameter = buildParams(parameterInfo, components, requestMethod,
291+
methodAttributes.getJsonViewAnnotation());
271292
// Merge with the operation parameters
272293
parameter = GenericParameterService.mergeParameter(operationParameters, parameter);
273294
List<Annotation> parameterAnnotations = Arrays.asList(methodParameter.getParameterAnnotations());
@@ -282,24 +303,45 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
282303
applyBeanValidatorAnnotations(parameter, parameterAnnotations);
283304
}
284305
else if (!RequestMethod.GET.equals(requestMethod)) {
285-
if (operation.getRequestBody() != null)
306+
if (operation.getRequestBody() != null) {
286307
requestBodyInfo.setRequestBody(operation.getRequestBody());
287-
requestBodyService.calculateRequestBodyInfo(components, methodAttributes,
288-
parameterInfo, requestBodyInfo);
308+
}
309+
requestBodyService.calculateRequestBodyInfo(components, methodAttributes, parameterInfo,
310+
requestBodyInfo);
289311
// Add requestBody javadoc
290-
if (StringUtils.isBlank(requestBodyInfo.getRequestBody().getDescription()) && javadocProvider != null) {
312+
if (StringUtils.isBlank(requestBodyInfo.getRequestBody().getDescription())
313+
&& javadocProvider != null) {
291314
String paramJavadocDescription = getParamJavadoc(javadocProvider, methodParameter, pName);
292315
if (!StringUtils.isBlank(paramJavadocDescription)) {
293316
requestBodyInfo.getRequestBody().setDescription(paramJavadocDescription);
294317
}
295318
}
296-
applyBeanValidatorAnnotations(requestBodyInfo.getRequestBody(), parameterAnnotations, methodParameter.isOptional());
319+
applyBeanValidatorAnnotations(requestBodyInfo.getRequestBody(), parameterAnnotations,
320+
methodParameter.isOptional());
297321
}
298322
customiseParameter(parameter, parameterInfo, operationParameters);
299323
}
300324
}
301325

302-
LinkedHashMap<String, Parameter> map = getParameterLinkedHashMap(components, methodAttributes, operationParameters, parametersDocMap);
326+
LinkedHashMap<String, Parameter> map = getParameterLinkedHashMap(components, methodAttributes,
327+
operationParameters, parametersDocMap);
328+
RequestBody body = requestBodyInfo.getRequestBody();
329+
// TODO support form-data
330+
if (body != null && body.getContent() != null && body.getContent().containsKey("multipart/form-data")) {
331+
Set<String> keys = map.keySet();
332+
io.swagger.v3.oas.models.media.Schema mergedSchema = requestBodyInfo.getMergedSchema();
333+
for (String key : keys) {
334+
Parameter parameter = map.get(key);
335+
io.swagger.v3.oas.models.media.Schema itemSchema = new io.swagger.v3.oas.models.media.Schema();
336+
itemSchema.setName(key);
337+
itemSchema.setDescription(parameter.getDescription());
338+
itemSchema.setDeprecated(parameter.getDeprecated());
339+
itemSchema.setExample(parameter.getExample());
340+
mergedSchema.addProperty(key, itemSchema);
341+
}
342+
map.clear();
343+
}
344+
// TODO support form-data END
303345
setParams(operation, new ArrayList<>(map.values()), requestBodyInfo);
304346
return operation;
305347
}
@@ -707,4 +749,98 @@ private String getParamJavadoc(JavadocProvider javadocProvider, MethodParameter
707749
return paramJavadocDescription;
708750
}
709751

752+
private io.swagger.v3.oas.annotations.Parameter generateParameterBySchema(io.swagger.v3.oas.annotations.media.Schema schema) {
753+
return new io.swagger.v3.oas.annotations.Parameter() {
754+
755+
@Override
756+
public Class<? extends Annotation> annotationType() {
757+
return io.swagger.v3.oas.annotations.Parameter.class;
758+
}
759+
760+
@Override
761+
public String name() {
762+
return schema.name();
763+
}
764+
765+
@Override
766+
public ParameterIn in() {
767+
return ParameterIn.DEFAULT;
768+
}
769+
770+
@Override
771+
public String description() {
772+
return schema.description();
773+
}
774+
775+
@Override
776+
public boolean required() {
777+
return schema.required();
778+
}
779+
780+
@Override
781+
public boolean deprecated() {
782+
return schema.deprecated();
783+
}
784+
785+
@Override
786+
public boolean allowEmptyValue() {
787+
return false;
788+
}
789+
790+
@Override
791+
public ParameterStyle style() {
792+
return ParameterStyle.DEFAULT;
793+
}
794+
795+
@Override
796+
public Explode explode() {
797+
return Explode.DEFAULT;
798+
}
799+
800+
@Override
801+
public boolean allowReserved() {
802+
return false;
803+
}
804+
805+
@Override
806+
public io.swagger.v3.oas.annotations.media.Schema schema() {
807+
return schema;
808+
}
809+
810+
@Override
811+
public ArraySchema array() {
812+
return null;
813+
}
814+
815+
@Override
816+
public io.swagger.v3.oas.annotations.media.Content[] content() {
817+
return new io.swagger.v3.oas.annotations.media.Content[0];
818+
}
819+
820+
@Override
821+
public boolean hidden() {
822+
return schema.hidden();
823+
}
824+
825+
@Override
826+
public ExampleObject[] examples() {
827+
return new ExampleObject[0];
828+
}
829+
830+
@Override
831+
public String example() {
832+
return schema.example();
833+
}
834+
835+
@Override
836+
public Extension[] extensions() {
837+
return schema.extensions();
838+
}
839+
840+
@Override
841+
public String ref() {
842+
return schema.ref();
843+
}
844+
};
845+
}
710846
}

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

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.Objects;
3636
import java.util.Optional;
3737

38+
import io.swagger.v3.oas.annotations.parameters.RequestBody;
3839
import org.apache.commons.lang3.ArrayUtils;
3940
import org.apache.commons.lang3.reflect.FieldUtils;
4041
import org.slf4j.Logger;
@@ -48,6 +49,8 @@
4849
import org.springframework.core.annotation.AnnotatedElementUtils;
4950
import org.springframework.lang.NonNull;
5051
import org.springframework.lang.Nullable;
52+
import org.springframework.web.bind.annotation.RequestMethod;
53+
import org.springframework.web.bind.annotation.RequestPart;
5154

5255
/**
5356
* The type Delegating method parameter.
@@ -58,22 +61,22 @@ public class DelegatingMethodParameter extends MethodParameter {
5861
/**
5962
* The Delegate.
6063
*/
61-
private final MethodParameter delegate;
64+
private MethodParameter delegate;
6265

6366
/**
6467
* The Additional parameter annotations.
6568
*/
66-
private final Annotation[] additionalParameterAnnotations;
69+
private Annotation[] additionalParameterAnnotations;
6770

6871
/**
6972
* The Parameter name.
7073
*/
71-
private final String parameterName;
74+
private String parameterName;
7275

7376
/**
7477
* The Is parameter object.
7578
*/
76-
private final boolean isParameterObject;
79+
private boolean isParameterObject;
7780

7881
/**
7982
* The Is not required.
@@ -87,14 +90,14 @@ public class DelegatingMethodParameter extends MethodParameter {
8790

8891
/**
8992
* Instantiates a new Delegating method parameter.
90-
*
9193
* @param delegate the delegate
9294
* @param parameterName the parameter name
9395
* @param additionalParameterAnnotations the additional parameter annotations
9496
* @param isParameterObject the is parameter object
9597
* @param isNotRequired the is required
9698
*/
97-
DelegatingMethodParameter(MethodParameter delegate, String parameterName, Annotation[] additionalParameterAnnotations, boolean isParameterObject, boolean isNotRequired) {
99+
public DelegatingMethodParameter(MethodParameter delegate, String parameterName,
100+
Annotation[] additionalParameterAnnotations, boolean isParameterObject, boolean isNotRequired) {
98101
super(delegate);
99102
this.delegate = delegate;
100103
this.additionalParameterAnnotations = additionalParameterAnnotations;
@@ -105,24 +108,41 @@ public class DelegatingMethodParameter extends MethodParameter {
105108

106109
/**
107110
* Customize method parameter [ ].
108-
*
109111
* @param pNames the p names
110112
* @param parameters the parameters
111-
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
113+
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method
114+
* parameter customizer
112115
* @return the method parameter [ ]
113116
*/
114-
public static MethodParameter[] customize(String[] pNames, MethodParameter[] parameters, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer) {
117+
public static MethodParameter[] customize(String[] pNames, MethodParameter[] parameters,
118+
Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
119+
RequestMethod requestMethod) {
115120
List<MethodParameter> explodedParameters = new ArrayList<>();
116121
for (int i = 0; i < parameters.length; ++i) {
117122
MethodParameter p = parameters[i];
118123
Class<?> paramClass = AdditionalModelsConverter.getParameterObjectReplacement(p.getParameterType());
119124

120-
if (!MethodParameterPojoExtractor.isSimpleType(paramClass) && (p.hasParameterAnnotation(ParameterObject.class) || AnnotatedElementUtils.isAnnotated(paramClass, ParameterObject.class))) {
125+
if (!MethodParameterPojoExtractor.isSimpleType(paramClass)
126+
&& (p.hasParameterAnnotation(ParameterObject.class)
127+
|| AnnotatedElementUtils.isAnnotated(paramClass, ParameterObject.class))) {
121128
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
122-
optionalDelegatingMethodParameterCustomizer.ifPresent(customizer -> customizer.customize(p, methodParameter));
129+
optionalDelegatingMethodParameterCustomizer
130+
.ifPresent(customizer -> customizer.customize(p, methodParameter));
123131
explodedParameters.add(methodParameter);
124132
});
125133
}
134+
// TODO remove @ParameterObject
135+
else if (!MethodParameterPojoExtractor.isSimpleType(paramClass)
136+
&& !(p.hasParameterAnnotation(RequestBody.class)
137+
|| p.hasParameterAnnotation(org.springframework.web.bind.annotation.RequestBody.class)
138+
|| p.hasParameterAnnotation(RequestPart.class))) {
139+
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
140+
optionalDelegatingMethodParameterCustomizer
141+
.ifPresent(customizer -> customizer.customize(p, methodParameter));
142+
explodedParameters.add(methodParameter);
143+
});
144+
}
145+
// TODO remove @ParameterObject END
126146
else {
127147
String name = pNames != null ? pNames[i] : p.getParameterName();
128148
explodedParameters.add(new DelegatingMethodParameter(p, name, null, false, false));
@@ -209,7 +229,6 @@ public void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDisc
209229

210230
/**
211231
* Is not required boolean.
212-
*
213232
* @return the boolean
214233
*/
215234
public boolean isNotRequired() {
@@ -218,7 +237,6 @@ public boolean isNotRequired() {
218237

219238
/**
220239
* Sets not required.
221-
*
222240
* @param notRequired the not required
223241
*/
224242
public void setNotRequired(boolean notRequired) {
@@ -227,13 +245,19 @@ public void setNotRequired(boolean notRequired) {
227245

228246
@Override
229247
public boolean equals(Object o) {
230-
if (this == o) return true;
231-
if (o == null || getClass() != o.getClass()) return false;
232-
if (!super.equals(o)) return false;
248+
if (this == o) {
249+
return true;
250+
}
251+
if (o == null || getClass() != o.getClass()) {
252+
return false;
253+
}
254+
if (!super.equals(o)) {
255+
return false;
256+
}
233257
DelegatingMethodParameter that = (DelegatingMethodParameter) o;
234-
return Objects.equals(delegate, that.delegate) &&
235-
Arrays.equals(additionalParameterAnnotations, that.additionalParameterAnnotations) &&
236-
Objects.equals(parameterName, that.parameterName);
258+
return Objects.equals(delegate, that.delegate)
259+
&& Arrays.equals(additionalParameterAnnotations, that.additionalParameterAnnotations)
260+
&& Objects.equals(parameterName, that.parameterName);
237261
}
238262

239263
@Override
@@ -245,22 +269,22 @@ public int hashCode() {
245269

246270
/**
247271
* Is parameter object boolean.
248-
*
249272
* @return the boolean
250273
*/
251274
public boolean isParameterObject() {
252275
return isParameterObject;
253276
}
254277

255278
/**
256-
* Return a variant of this {@code MethodParameter} which refers to the
257-
* given containing class.
258-
* @param methodParameter the method parameter
259-
* @param containingClass a specific containing class (potentially a subclass of the declaring class, e.g. substituting a type variable) A copy of spring withContainingClass, to keep compatibility with older spring versions
260-
* @return the method parameter
261-
* @see #getParameterType() #getParameterType()
279+
* Return a variant of this {@code MethodParameter} which refers to the given
280+
* containing class.
281+
* @param containingClass a specific containing class (potentially a subclass of the
282+
* declaring class, e.g. substituting a type variable) A copy of spring
283+
* withContainingClass, to keep compatibility with older spring versions
284+
* @see #getParameterType()
262285
*/
263-
public static MethodParameter changeContainingClass(MethodParameter methodParameter, @Nullable Class<?> containingClass) {
286+
public static MethodParameter changeContainingClass(MethodParameter methodParameter,
287+
@Nullable Class<?> containingClass) {
264288
MethodParameter result = methodParameter.clone();
265289
try {
266290
Field containingClassField = FieldUtils.getDeclaredField(result.getClass(), "containingClass", true);

0 commit comments

Comments
 (0)