Skip to content

Commit d4a6d76

Browse files
committed
support get javadoc description from getter method
1 parent ffc7ad2 commit d4a6d76

File tree

6 files changed

+276
-8
lines changed

6 files changed

+276
-8
lines changed

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

Lines changed: 22 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;
@@ -76,15 +76,19 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato
7676
Class<?> cls = javaType.getRawClass();
7777
Schema<?> resolvedSchema = chain.next().resolve(type, context, chain);
7878
List<Field> fields = FieldUtils.getAllFieldsList(cls);
79-
if (!CollectionUtils.isEmpty(fields)) {
79+
List<PropertyDescriptor> clsProperties = new ArrayList<>();
80+
try {
81+
clsProperties = Arrays.asList(Introspector.getBeanInfo(cls).getPropertyDescriptors());
82+
} catch (IntrospectionException ignored) {}
83+
if (!CollectionUtils.isEmpty(fields) || !CollectionUtils.isEmpty(clsProperties)) {
8084
if (!type.isSchemaProperty()) {
8185
Schema existingSchema = context.resolve(type);
82-
setJavadocDescription(cls, fields, existingSchema);
86+
setJavadocDescription(cls, fields, clsProperties, existingSchema);
8387
}
8488
else if (resolvedSchema != null && resolvedSchema.get$ref() != null && resolvedSchema.get$ref().contains(AnnotationsUtils.COMPONENTS_REF)) {
8589
String schemaName = resolvedSchema.get$ref().substring(21);
8690
Schema existingSchema = context.getDefinedModels().get(schemaName);
87-
setJavadocDescription(cls, fields, existingSchema);
91+
setJavadocDescription(cls, fields, clsProperties, existingSchema);
8892
}
8993
}
9094
return resolvedSchema;
@@ -96,10 +100,12 @@ else if (resolvedSchema != null && resolvedSchema.get$ref() != null && resolvedS
96100
/**
97101
* Sets javadoc description.
98102
*
103+
* @param cls the cls
99104
* @param fields the fields
105+
* @param clsProperties the bean properties of cls
100106
* @param existingSchema the existing schema
101107
*/
102-
private void setJavadocDescription(Class<?> cls, List<Field> fields, Schema existingSchema) {
108+
private void setJavadocDescription(Class<?> cls, List<Field> fields, List<PropertyDescriptor> clsProperties, Schema existingSchema) {
103109
if (existingSchema != null) {
104110
if (StringUtils.isBlank(existingSchema.getDescription())) {
105111
existingSchema.setDescription(javadocProvider.getClassJavadoc(cls));
@@ -124,6 +130,14 @@ private void setJavadocDescription(Class<?> cls, List<Field> fields, Schema exis
124130
if (StringUtils.isNotBlank(fieldJavadoc))
125131
stringSchemaEntry.getValue().setDescription(fieldJavadoc);
126132
});
133+
if (StringUtils.isBlank(stringSchemaEntry.getValue().getDescription())) {
134+
Optional<PropertyDescriptor> optionalPd = clsProperties.stream().filter(pd -> pd.getName().equals(stringSchemaEntry.getKey())).findAny();
135+
optionalPd.ifPresent(pd1 -> {
136+
String fieldJavadoc = javadocProvider.getMethodJavadocDescription(pd1.getReadMethod());
137+
if (StringUtils.isNotBlank(fieldJavadoc))
138+
stringSchemaEntry.getValue().setDescription(fieldJavadoc);
139+
});
140+
}
127141
});
128142
}
129143
}
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.app170;
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.app170;
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.app170;
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,34 @@
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.app170;
20+
21+
import org.springframework.boot.autoconfigure.SpringBootApplication;
22+
import test.org.springdoc.api.AbstractSpringDocTest;
23+
24+
/**
25+
* The type Spring doc app 170 test.
26+
*/
27+
public class SpringDocApp170Test extends AbstractSpringDocTest {
28+
29+
/**
30+
* The type Spring doc test app.
31+
*/
32+
@SpringBootApplication
33+
static class SpringDocTestApp {}
34+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"tags": [
14+
{
15+
"name": "hello-controller",
16+
"description": "The type Hello controller."
17+
}
18+
],
19+
"paths": {
20+
"/persons": {
21+
"get": {
22+
"tags": [
23+
"hello-controller"
24+
],
25+
"summary": "PersonProjection interface.",
26+
"description": "PersonProjection interface.",
27+
"operationId": "persons",
28+
"responses": {
29+
"200": {
30+
"description": "the PersonProjection",
31+
"content": {
32+
"*/*": {
33+
"schema": {
34+
"$ref": "#/components/schemas/PersonProjection"
35+
}
36+
}
37+
}
38+
}
39+
}
40+
}
41+
}
42+
},
43+
"components": {
44+
"schemas": {
45+
"PersonProjection" : {
46+
"type" : "object",
47+
"properties" : {
48+
"email" : {
49+
"type" : "string",
50+
"description" : "The Email."
51+
},
52+
"firstName" : {
53+
"type" : "string",
54+
"description" : "The First name."
55+
},
56+
"lastName" : {
57+
"type" : "string",
58+
"description" : "The Last name."
59+
}
60+
},
61+
"description" : "The type PersonProjection dto interface."
62+
}
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)