Skip to content

Commit 74b2932

Browse files
committed
Support get javadoc description from getter method review
2 parents 1d94e47 + 7dfc405 commit 74b2932

File tree

12 files changed

+446
-36
lines changed

12 files changed

+446
-36
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/JavadocPropertyCustomizer.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424

2525
package org.springdoc.core.customizers;
2626

27+
import java.beans.IntrospectionException;
28+
import java.beans.Introspector;
29+
import java.beans.PropertyDescriptor;
2730
import java.lang.reflect.Field;
28-
import java.util.Iterator;
29-
import java.util.List;
30-
import java.util.Map;
31-
import java.util.Optional;
31+
import java.util.*;
3232

3333
import com.fasterxml.jackson.databind.JavaType;
3434
import io.swagger.v3.core.converter.AnnotatedType;
@@ -38,6 +38,9 @@
3838
import io.swagger.v3.oas.models.media.Schema;
3939
import org.apache.commons.lang3.StringUtils;
4040
import org.apache.commons.lang3.reflect.FieldUtils;
41+
import org.slf4j.Logger;
42+
import org.slf4j.LoggerFactory;
43+
import org.springdoc.core.extractor.DelegatingMethodParameter;
4144
import org.springdoc.core.providers.JavadocProvider;
4245
import org.springdoc.core.providers.ObjectMapperProvider;
4346

@@ -51,6 +54,7 @@ public record JavadocPropertyCustomizer(JavadocProvider javadocProvider,
5154
ObjectMapperProvider objectMapperProvider)
5255
implements ModelConverter {
5356

57+
private static final Logger LOGGER = LoggerFactory.getLogger(DelegatingMethodParameter.class);
5458
/**
5559
* Instantiates a new Javadoc property customizer.
5660
*
@@ -76,15 +80,21 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato
7680
Class<?> cls = javaType.getRawClass();
7781
Schema<?> resolvedSchema = chain.next().resolve(type, context, chain);
7882
List<Field> fields = FieldUtils.getAllFieldsList(cls);
79-
if (!CollectionUtils.isEmpty(fields)) {
83+
List<PropertyDescriptor> clsProperties = new ArrayList<>();
84+
try {
85+
clsProperties = Arrays.asList(Introspector.getBeanInfo(cls).getPropertyDescriptors());
86+
} catch (IntrospectionException ignored) {
87+
LOGGER.warn(ignored.getMessage());
88+
}
89+
if (!CollectionUtils.isEmpty(fields) || !CollectionUtils.isEmpty(clsProperties)) {
8090
if (!type.isSchemaProperty()) {
8191
Schema existingSchema = context.resolve(type);
82-
setJavadocDescription(cls, fields, existingSchema);
92+
setJavadocDescription(cls, fields, clsProperties, existingSchema);
8393
}
8494
else if (resolvedSchema != null && resolvedSchema.get$ref() != null && resolvedSchema.get$ref().contains(AnnotationsUtils.COMPONENTS_REF)) {
8595
String schemaName = resolvedSchema.get$ref().substring(21);
8696
Schema existingSchema = context.getDefinedModels().get(schemaName);
87-
setJavadocDescription(cls, fields, existingSchema);
97+
setJavadocDescription(cls, fields, clsProperties, existingSchema);
8898
}
8999
}
90100
return resolvedSchema;
@@ -96,10 +106,12 @@ else if (resolvedSchema != null && resolvedSchema.get$ref() != null && resolvedS
96106
/**
97107
* Sets javadoc description.
98108
*
109+
* @param cls the cls
99110
* @param fields the fields
111+
* @param clsProperties the bean properties of cls
100112
* @param existingSchema the existing schema
101113
*/
102-
private void setJavadocDescription(Class<?> cls, List<Field> fields, Schema existingSchema) {
114+
public void setJavadocDescription(Class<?> cls, List<Field> fields, List<PropertyDescriptor> clsProperties, Schema existingSchema) {
103115
if (existingSchema != null) {
104116
if (StringUtils.isBlank(existingSchema.getDescription())) {
105117
String classJavadoc = javadocProvider.getClassJavadoc(cls);
@@ -127,6 +139,14 @@ private void setJavadocDescription(Class<?> cls, List<Field> fields, Schema exis
127139
if (StringUtils.isNotBlank(fieldJavadoc))
128140
stringSchemaEntry.getValue().setDescription(fieldJavadoc);
129141
});
142+
if (StringUtils.isBlank(stringSchemaEntry.getValue().getDescription())) {
143+
Optional<PropertyDescriptor> optionalPd = clsProperties.stream().filter(pd -> pd.getName().equals(stringSchemaEntry.getKey())).findAny();
144+
optionalPd.ifPresent(pd1 -> {
145+
String fieldJavadoc = javadocProvider.getMethodJavadocDescription(pd1.getReadMethod());
146+
if (StringUtils.isNotBlank(fieldJavadoc))
147+
stringSchemaEntry.getValue().setDescription(fieldJavadoc);
148+
});
149+
}
130150
});
131151
}
132152
}

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

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* *
44
* * *
55
* * * *
6-
* * * * * Copyright 2019-2022 the original author or authors.
6+
* * * * * Copyright 2019-2023 the original author or authors.
77
* * * * *
88
* * * * * Licensed under the Apache License, Version 2.0 (the "License");
99
* * * * * you may not use this file except in compliance with the License.
@@ -124,31 +124,16 @@ public static MethodParameter[] customize(String[] pNames, MethodParameter[] par
124124
MethodParameter p = parameters[i];
125125
Class<?> paramClass = AdditionalModelsConverter.getParameterObjectReplacement(p.getParameterType());
126126

127-
if (!MethodParameterPojoExtractor.isSimpleType(paramClass) && (p.hasParameterAnnotation(ParameterObject.class) || AnnotatedElementUtils.isAnnotated(paramClass, ParameterObject.class))) {
127+
boolean hasFlatAnnotation = p.hasParameterAnnotation(ParameterObject.class) || AnnotatedElementUtils.isAnnotated(paramClass, ParameterObject.class);
128+
boolean hasNotFlatAnnotation = Arrays.stream(p.getParameterAnnotations())
129+
.anyMatch(annotation -> Arrays.asList(RequestBody.class, RequestPart.class).contains(annotation.annotationType()));
130+
if (!MethodParameterPojoExtractor.isSimpleType(paramClass)
131+
&& (hasFlatAnnotation || (defaultFlatParamObject && !hasNotFlatAnnotation && !AbstractRequestService.isRequestTypeToIgnore(paramClass)))) {
128132
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
129133
optionalDelegatingMethodParameterCustomizer.ifPresent(customizer -> customizer.customize(p, methodParameter));
130134
explodedParameters.add(methodParameter);
131135
});
132136
}
133-
else if (defaultFlatParamObject) {
134-
boolean isSimpleType = MethodParameterPojoExtractor.isSimpleType(paramClass);
135-
List<Annotation> annotations = Arrays.stream(p.getParameterAnnotations())
136-
.filter(annotation -> Arrays.asList(RequestBody.class, RequestPart.class).contains(annotation.annotationType()))
137-
.toList();
138-
boolean hasAnnotation = !annotations.isEmpty();
139-
boolean shouldFlat = !isSimpleType && !hasAnnotation;
140-
if (shouldFlat && !AbstractRequestService.isRequestTypeToIgnore(paramClass)) {
141-
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
142-
optionalDelegatingMethodParameterCustomizer
143-
.ifPresent(customizer -> customizer.customize(p, methodParameter));
144-
explodedParameters.add(methodParameter);
145-
});
146-
}
147-
else {
148-
String name = pNames != null ? pNames[i] : p.getParameterName();
149-
explodedParameters.add(new DelegatingMethodParameter(p, name, null, false, false));
150-
}
151-
}
152137
else {
153138
String name = pNames != null ? pNames[i] : p.getParameterName();
154139
explodedParameters.add(new DelegatingMethodParameter(p, name, null, false, false));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
*
3+
* * Copyright 2019-2023 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 test.org.springdoc.api.app171;
20+
21+
import org.springframework.web.bind.annotation.GetMapping;
22+
import org.springframework.web.bind.annotation.RestController;
23+
24+
/**
25+
* The type Hello controller.
26+
*/
27+
@RestController
28+
public class HelloController {
29+
30+
/**
31+
* PersonProjection interface.
32+
*
33+
* @return the PersonProjection
34+
*/
35+
@GetMapping(value = "/persons")
36+
public PersonProjection persons() {
37+
return new PersonDTO();
38+
}
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
*
3+
* * Copyright 2019-2023 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 test.org.springdoc.api.app171;
20+
21+
/**
22+
* Simulate a dynamically generated class that implements the PersonProjection interface.
23+
*/
24+
public class PersonDTO implements PersonProjection {
25+
private String email;
26+
27+
private String firstName;
28+
29+
private String lastName;
30+
31+
/**
32+
* Instantiates a new Person dto.
33+
*/
34+
public PersonDTO() {
35+
}
36+
37+
/**
38+
* Instantiates a new Person dto.
39+
*
40+
* @param email the email
41+
* @param firstName the first name
42+
* @param lastName the last name
43+
*/
44+
public PersonDTO(final String email, final String firstName, final String lastName) {
45+
this.email = email;
46+
this.firstName = firstName;
47+
this.lastName = lastName;
48+
}
49+
50+
public String getEmail() {
51+
return email;
52+
}
53+
54+
public void setEmail(final String email) {
55+
this.email = email;
56+
}
57+
58+
public String getFirstName() {
59+
return firstName;
60+
}
61+
62+
public void setFirstName(final String firstName) {
63+
this.firstName = firstName;
64+
}
65+
66+
public String getLastName() {
67+
return lastName;
68+
}
69+
70+
public void setLastName(final String lastName) {
71+
this.lastName = lastName;
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
*
3+
* * Copyright 2019-2023 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 test.org.springdoc.api.app171;
20+
21+
/**
22+
* The type PersonProjection dto interface.
23+
*/
24+
public interface PersonProjection {
25+
/**
26+
* The Email.
27+
*
28+
*/
29+
String getEmail();
30+
31+
/**
32+
* The First name.
33+
*
34+
*/
35+
String getFirstName();
36+
37+
/**
38+
* The Last name.
39+
*
40+
*/
41+
String getLastName();
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
*
3+
* * Copyright 2019-2023 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 test.org.springdoc.api.app171;
20+
21+
import test.org.springdoc.api.AbstractSpringDocTest;
22+
23+
import org.springframework.boot.autoconfigure.SpringBootApplication;
24+
25+
/**
26+
* The type Spring doc app 193 test.
27+
*/
28+
public class SpringDocApp171Test extends AbstractSpringDocTest {
29+
30+
/**
31+
* The type Spring doc test app.
32+
*/
33+
@SpringBootApplication
34+
static class SpringDocTestApp {
35+
}
36+
37+
}

0 commit comments

Comments
 (0)