Skip to content

Commit 42b76f9

Browse files
committed
Javadoc description of the @RequestPart param of multipart/form-data goes to requestBody description, not to parameter description. Fixes #1923
1 parent 8b01535 commit 42b76f9

File tree

17 files changed

+300
-265
lines changed

17 files changed

+300
-265
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,16 +271,15 @@ ModelConverterRegistrar modelConverterRegistrar(Optional<List<ModelConverter>> m
271271
* @param requestBodyService the request body service
272272
* @param securityParser the security parser
273273
* @param propertyResolverUtils the property resolver utils
274-
* @param javadocProvider the javadoc provider
275274
* @return the operation service
276275
*/
277276
@Bean
278277
@ConditionalOnMissingBean
279278
@Lazy(false)
280279
OperationService operationBuilder(GenericParameterService parameterBuilder, RequestBodyService requestBodyService,
281-
SecurityService securityParser, PropertyResolverUtils propertyResolverUtils, Optional<JavadocProvider> javadocProvider) {
280+
SecurityService securityParser, PropertyResolverUtils propertyResolverUtils) {
282281
return new OperationService(parameterBuilder, requestBodyService,
283-
securityParser, propertyResolverUtils, javadocProvider);
282+
securityParser, propertyResolverUtils);
284283
}
285284

286285
/**
@@ -341,16 +340,17 @@ ReturnTypeParser genericReturnTypeParser() {
341340
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
342341
* @param optionalWebConversionServiceProvider the optional web conversion service provider
343342
* @param objectMapperProvider the object mapper provider
343+
* @param javadocProvider the javadoc provider
344344
* @return the generic parameter builder
345345
*/
346346
@Bean
347347
@ConditionalOnMissingBean
348348
@Lazy(false)
349349
GenericParameterService parameterBuilder(PropertyResolverUtils propertyResolverUtils,
350350
Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
351-
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
351+
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider,Optional<JavadocProvider> javadocProvider) {
352352
return new GenericParameterService(propertyResolverUtils, optionalDelegatingMethodParameterCustomizer,
353-
optionalWebConversionServiceProvider, objectMapperProvider);
353+
optionalWebConversionServiceProvider, objectMapperProvider,javadocProvider);
354354
}
355355

356356
/**

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

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
package org.springdoc.core.service;
2626

2727
import java.lang.annotation.Annotation;
28-
import java.lang.reflect.Field;
2928
import java.lang.reflect.Method;
3029
import java.math.BigDecimal;
3130
import java.util.ArrayList;
@@ -64,7 +63,6 @@
6463
import jakarta.validation.constraints.Size;
6564
import org.apache.commons.lang3.ArrayUtils;
6665
import org.apache.commons.lang3.StringUtils;
67-
import org.apache.commons.lang3.reflect.FieldUtils;
6866
import org.springdoc.core.customizers.ParameterCustomizer;
6967
import org.springdoc.core.extractor.DelegatingMethodParameter;
7068
import org.springdoc.core.models.MethodAttributes;
@@ -95,7 +93,6 @@
9593
import org.springframework.web.util.UriComponentsBuilder;
9694

9795
import static org.springdoc.core.converters.SchemaPropertyDeprecatingConverter.containsDeprecatedAnnotation;
98-
import static org.springdoc.core.utils.Constants.DOT;
9996
import static org.springdoc.core.utils.Constants.OPENAPI_ARRAY_TYPE;
10097
import static org.springdoc.core.utils.Constants.OPENAPI_STRING_TYPE;
10198

@@ -264,7 +261,7 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
264261
Map<ParameterId, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(handlerMethod.getMethod());
265262
Components components = openAPI.getComponents();
266263

267-
JavadocProvider javadocProvider = operationService.getJavadocProvider();
264+
JavadocProvider javadocProvider = parameterBuilder.getJavadocProvider();
268265

269266
for (MethodParameter methodParameter : parameters) {
270267
// check if query param
@@ -304,7 +301,7 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
304301
if (isValidParameter(parameter)) {
305302
// Add param javadoc
306303
if (StringUtils.isBlank(parameter.getDescription()) && javadocProvider != null) {
307-
String paramJavadocDescription = getParamJavadoc(javadocProvider, methodParameter, pName);
304+
String paramJavadocDescription = parameterBuilder.getParamJavadoc(javadocProvider, methodParameter);
308305
if (!StringUtils.isBlank(paramJavadocDescription)) {
309306
parameter.setDescription(paramJavadocDescription);
310307
}
@@ -316,13 +313,6 @@ else if (!RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1.
316313
requestBodyInfo.setRequestBody(operation.getRequestBody());
317314
requestBodyService.calculateRequestBodyInfo(components, methodAttributes,
318315
parameterInfo, requestBodyInfo);
319-
// Add requestBody javadoc
320-
if (StringUtils.isBlank(requestBodyInfo.getRequestBody().getDescription()) && javadocProvider != null) {
321-
String paramJavadocDescription = getParamJavadoc(javadocProvider, methodParameter, pName);
322-
if (!StringUtils.isBlank(paramJavadocDescription)) {
323-
requestBodyInfo.getRequestBody().setDescription(paramJavadocDescription);
324-
}
325-
}
326316
applyBeanValidatorAnnotations(requestBodyInfo.getRequestBody(), parameterAnnotations, methodParameter.isOptional());
327317
}
328318
customiseParameter(parameter, parameterInfo, operationParameters);
@@ -741,31 +731,6 @@ private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo pa
741731
|| (!ClassUtils.isPrimitiveOrWrapper(methodParameter.getParameterType()) && (!ArrayUtils.isEmpty(methodParameter.getParameterAnnotations()))));
742732
}
743733

744-
/**
745-
* Gets param javadoc.
746-
*
747-
* @param javadocProvider the javadoc provider
748-
* @param methodParameter the method parameter
749-
* @param pName the p name
750-
* @return the param javadoc
751-
*/
752-
private String getParamJavadoc(JavadocProvider javadocProvider, MethodParameter methodParameter, String pName) {
753-
DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
754-
final String paramJavadocDescription;
755-
if (delegatingMethodParameter.isParameterObject()) {
756-
String fieldName;
757-
if (StringUtils.isNotEmpty(pName) && pName.contains(DOT))
758-
fieldName = StringUtils.substringAfterLast(pName, DOT);
759-
else
760-
fieldName = pName;
761-
Field field = FieldUtils.getDeclaredField(((DelegatingMethodParameter) methodParameter).getExecutable().getDeclaringClass(), fieldName, true);
762-
paramJavadocDescription = javadocProvider.getFieldJavadoc(field);
763-
}
764-
else
765-
paramJavadocDescription = javadocProvider.getParamJavadoc(methodParameter.getMethod(), pName);
766-
return paramJavadocDescription;
767-
}
768-
769734
/**
770735
* Is default flat param object boolean.
771736
*

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericParameterService.java

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.io.IOException;
2828
import java.lang.annotation.Annotation;
29+
import java.lang.reflect.Field;
2930
import java.lang.reflect.ParameterizedType;
3031
import java.lang.reflect.Type;
3132
import java.lang.reflect.WildcardType;
@@ -36,6 +37,7 @@
3637
import java.util.List;
3738
import java.util.Locale;
3839
import java.util.Map;
40+
import java.util.Objects;
3941
import java.util.Optional;
4042

4143
import com.fasterxml.jackson.annotation.JsonView;
@@ -55,13 +57,16 @@
5557
import io.swagger.v3.oas.models.media.Schema;
5658
import io.swagger.v3.oas.models.parameters.Parameter;
5759
import org.apache.commons.lang3.StringUtils;
60+
import org.apache.commons.lang3.reflect.FieldUtils;
5861
import org.slf4j.Logger;
5962
import org.slf4j.LoggerFactory;
6063
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
64+
import org.springdoc.core.extractor.DelegatingMethodParameter;
6165
import org.springdoc.core.extractor.MethodParameterPojoExtractor;
6266
import org.springdoc.core.models.ParameterInfo;
6367
import org.springdoc.core.models.RequestBodyInfo;
6468
import org.springdoc.core.parsers.ReturnTypeParser;
69+
import org.springdoc.core.providers.JavadocProvider;
6570
import org.springdoc.core.providers.ObjectMapperProvider;
6671
import org.springdoc.core.providers.WebConversionServiceProvider;
6772
import org.springdoc.core.utils.Constants;
@@ -73,11 +78,14 @@
7378
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
7479
import org.springframework.core.MethodParameter;
7580
import org.springframework.core.ResolvableType;
81+
import org.springframework.core.annotation.AnnotatedElementUtils;
7682
import org.springframework.core.io.Resource;
7783
import org.springframework.web.context.request.RequestScope;
7884
import org.springframework.web.multipart.MultipartFile;
7985
import org.springframework.web.multipart.MultipartRequest;
8086

87+
import static org.springdoc.core.utils.Constants.DOT;
88+
8189
/**
8290
* The type Generic parameter builder.
8391
* @author bnasslahsen, coutin
@@ -131,21 +139,28 @@ public class GenericParameterService {
131139
*/
132140
private final ObjectMapperProvider objectMapperProvider;
133141

142+
/**
143+
* The javadoc provider.
144+
*/
145+
private final Optional<JavadocProvider> javadocProviderOptional;
146+
134147
/**
135148
* Instantiates a new Generic parameter builder.
136149
* @param propertyResolverUtils the property resolver utils
137150
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
138151
* @param optionalWebConversionServiceProvider the optional web conversion service provider
139152
* @param objectMapperProvider the object mapper provider
153+
* @param javadocProviderOptional the javadoc provider
140154
*/
141155
public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
142-
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
156+
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider, Optional<JavadocProvider> javadocProviderOptional) {
143157
this.propertyResolverUtils = propertyResolverUtils;
144158
this.optionalDelegatingMethodParameterCustomizer = optionalDelegatingMethodParameterCustomizer;
145159
this.optionalWebConversionServiceProvider = optionalWebConversionServiceProvider;
146160
this.configurableBeanFactory = propertyResolverUtils.getFactory();
147161
this.expressionContext = (configurableBeanFactory != null ? new BeanExpressionContext(configurableBeanFactory, new RequestScope()) : null);
148162
this.objectMapperProvider = objectMapperProvider;
163+
this.javadocProviderOptional = javadocProviderOptional;
149164
}
150165

151166
/**
@@ -359,6 +374,16 @@ Schema calculateSchema(Components components, ParameterInfo parameterInfo, Reque
359374

360375
if (requestBodyInfo != null) {
361376
schemaN = calculateRequestBodySchema(components, parameterInfo, requestBodyInfo, schemaN, paramName);
377+
JavadocProvider javadocProvider = javadocProviderOptional.orElse(null);
378+
if (schemaN != null && javadocProvider != null && !isRequestBodyPresent(parameterInfo)) {
379+
String paramJavadocDescription = getParamJavadoc(javadocProvider, methodParameter);
380+
if (schemaN.getProperties() != null && schemaN.getProperties().containsKey(parameterInfo.getpName())) {
381+
Map<String, Schema> properties = schemaN.getProperties();
382+
if (!StringUtils.isBlank(paramJavadocDescription) && StringUtils.isBlank(properties.get(parameterInfo.getpName()).getDescription())) {
383+
properties.get(parameterInfo.getpName()).setDescription(paramJavadocDescription);
384+
}
385+
}
386+
}
362387
}
363388

364389
return schemaN;
@@ -666,4 +691,48 @@ public String ref() {
666691
}
667692
};
668693
}
694+
695+
/**
696+
* Gets javadoc provider.
697+
*
698+
* @return the javadoc provider
699+
*/
700+
public JavadocProvider getJavadocProvider() {
701+
return javadocProviderOptional.orElse(null);
702+
}
703+
704+
/**
705+
* Is request body present boolean.
706+
*
707+
* @param parameterInfo the parameter info
708+
* @return the boolean
709+
*/
710+
public boolean isRequestBodyPresent(ParameterInfo parameterInfo) {
711+
return parameterInfo.getMethodParameter().getParameterAnnotation(io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null
712+
|| parameterInfo.getMethodParameter().getParameterAnnotation(org.springframework.web.bind.annotation.RequestBody.class) != null
713+
|| AnnotatedElementUtils.findMergedAnnotation(Objects.requireNonNull(parameterInfo.getMethodParameter().getMethod()), io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null;
714+
}
715+
716+
/**
717+
* Gets param javadoc.
718+
*
719+
* @param javadocProvider the javadoc provider
720+
* @param methodParameter the method parameter
721+
* @return the param javadoc
722+
*/
723+
String getParamJavadoc(JavadocProvider javadocProvider, MethodParameter methodParameter) {
724+
String pName = methodParameter.getParameterName();
725+
DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
726+
final String paramJavadocDescription;
727+
if (delegatingMethodParameter.isParameterObject()) {
728+
String fieldName; if (StringUtils.isNotEmpty(pName) && pName.contains(DOT))
729+
fieldName = StringUtils.substringAfterLast(pName, DOT);
730+
else fieldName = pName;
731+
Field field = FieldUtils.getDeclaredField(((DelegatingMethodParameter) methodParameter).getExecutable().getDeclaringClass(), fieldName, true);
732+
paramJavadocDescription = javadocProvider.getFieldJavadoc(field);
733+
}
734+
else
735+
paramJavadocDescription = javadocProvider.getParamJavadoc(methodParameter.getMethod(), pName);
736+
return paramJavadocDescription;
737+
}
669738
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OperationService.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,27 +94,20 @@ public class OperationService {
9494
*/
9595
private final PropertyResolverUtils propertyResolverUtils;
9696

97-
/**
98-
* The javadoc provider.
99-
*/
100-
private final Optional<JavadocProvider> javadocProvider;
101-
10297
/**
10398
* Instantiates a new Operation builder.
10499
* @param parameterBuilder the parameter builder
105100
* @param requestBodyService the request body builder
106101
* @param securityParser the security parser
107102
* @param propertyResolverUtils the property resolver utils
108-
* @param javadocProvider the javadoc provider
109103
*/
110104
public OperationService(GenericParameterService parameterBuilder, RequestBodyService requestBodyService,
111-
SecurityService securityParser, PropertyResolverUtils propertyResolverUtils, Optional<JavadocProvider> javadocProvider) {
105+
SecurityService securityParser, PropertyResolverUtils propertyResolverUtils) {
112106
super();
113107
this.parameterBuilder = parameterBuilder;
114108
this.requestBodyService = requestBodyService;
115109
this.securityParser = securityParser;
116110
this.propertyResolverUtils = propertyResolverUtils;
117-
this.javadocProvider = javadocProvider;
118111
}
119112

120113
/**
@@ -628,12 +621,12 @@ public Operation mergeOperation(Operation operation, Operation operationModel) {
628621
return operation;
629622
}
630623

631-
/**
624+
/**
632625
* Gets javadoc provider.
633626
*
634627
* @return the javadoc provider
635628
*/
636629
public JavadocProvider getJavadocProvider() {
637-
return javadocProvider.orElse(null);
630+
return parameterBuilder.getJavadocProvider();
638631
}
639632
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/RequestBodyService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,16 @@ else if (!methodAttributes.isWithResponseBodySchemaDoc()) {
287287
methodAttributes.getJsonViewAnnotationForRequestBody());
288288
mergeContent(requestBody, methodAttributes, schema);
289289
}
290+
291+
292+
// Add requestBody javadoc
293+
if (StringUtils.isBlank(requestBody.getDescription()) && parameterBuilder.getJavadocProvider() != null
294+
&& parameterBuilder.isRequestBodyPresent(parameterInfo)) {
295+
String paramJavadocDescription = parameterBuilder.getParamJavadoc(parameterBuilder.getJavadocProvider(), parameterInfo.getMethodParameter());
296+
if (!StringUtils.isBlank(paramJavadocDescription)) {
297+
requestBodyInfo.getRequestBody().setDescription(paramJavadocDescription);
298+
}
299+
}
290300
return requestBody;
291301
}
292302

springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWebMvcConfigurer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151

5252
import static org.springdoc.core.utils.Constants.CLASSPATH_RESOURCE_LOCATION;
5353
import static org.springdoc.core.utils.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
54+
import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_JS;
5455
import static org.springdoc.core.utils.Constants.SWAGGER_UI_PREFIX;
5556
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
56-
import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_JS;
5757
/**
5858
* The type Swagger web mvc configurer.
5959
* @author bnasslahsen

springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app103.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
"description": "Post my request body string.",
2727
"operationId": "postMyRequestBody",
2828
"requestBody": {
29-
"description": "the body",
3029
"content": {
3130
"multipart/form-data": {
3231
"schema": {
@@ -41,6 +40,7 @@
4140
},
4241
"file": {
4342
"type": "string",
43+
"description": "the file",
4444
"format": "binary"
4545
}
4646
}
@@ -87,4 +87,4 @@
8787
}
8888
}
8989
}
90-
}
90+
}

0 commit comments

Comments
 (0)