Skip to content

Commit 460d543

Browse files
committed
Improve support for externalizing strings in generated openapi schema via… #2418
1 parent 1a9c257 commit 460d543

File tree

5 files changed

+253
-55
lines changed

5 files changed

+253
-55
lines changed

Diff for: springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/SpecPropertiesCustomizer.java

+91-32
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import io.swagger.v3.oas.models.OpenAPI;
3434
import io.swagger.v3.oas.models.Operation;
3535
import io.swagger.v3.oas.models.PathItem;
36+
import io.swagger.v3.oas.models.PathItem.HttpMethod;
3637
import io.swagger.v3.oas.models.Paths;
3738
import io.swagger.v3.oas.models.info.Contact;
3839
import io.swagger.v3.oas.models.info.Info;
@@ -84,12 +85,25 @@
8485
*/
8586
public class SpecPropertiesCustomizer implements GlobalOpenApiCustomizer {
8687

88+
/**
89+
* The Open api properties.
90+
*/
8791
private final OpenAPI openApiProperties;
8892

93+
/**
94+
* Instantiates a new Spec properties customizer.
95+
*
96+
* @param springDocConfigProperties the spring doc config properties
97+
*/
8998
public SpecPropertiesCustomizer(SpringDocConfigProperties springDocConfigProperties) {
9099
this.openApiProperties = springDocConfigProperties.getOpenApi();
91100
}
92101

102+
/**
103+
* Instantiates a new Spec properties customizer.
104+
*
105+
* @param openApiProperties the open api properties
106+
*/
93107
public SpecPropertiesCustomizer(OpenAPI openApiProperties) {
94108
this.openApiProperties = openApiProperties;
95109
}
@@ -99,6 +113,12 @@ public void customise(OpenAPI openApi) {
99113
customizeOpenApi(openApi, openApiProperties);
100114
}
101115

116+
/**
117+
* Customize open api.
118+
*
119+
* @param openApi the open api
120+
* @param openApiProperties the open api properties
121+
*/
102122
private void customizeOpenApi(OpenAPI openApi, OpenAPI openApiProperties) {
103123
if (openApiProperties != null) {
104124
Info infoProperties = openApiProperties.getInfo();
@@ -108,12 +128,19 @@ private void customizeOpenApi(OpenAPI openApi, OpenAPI openApiProperties) {
108128
Components componentsProperties = openApiProperties.getComponents();
109129
if (componentsProperties != null)
110130
customizeComponents(openApi, componentsProperties);
131+
111132
Paths pathsProperties = openApiProperties.getPaths();
112133
if (pathsProperties != null)
113134
customizePaths(openApi, pathsProperties);
114135
}
115136
}
116137

138+
/**
139+
* Customize paths.
140+
*
141+
* @param openApi the open api
142+
* @param pathsProperties the paths properties
143+
*/
117144
private void customizePaths(OpenAPI openApi, Paths pathsProperties) {
118145
Paths paths = openApi.getPaths();
119146
if (paths == null) {
@@ -126,20 +153,30 @@ private void customizePaths(OpenAPI openApi, Paths pathsProperties) {
126153
}
127154
PathItem pathItemProperties = pathsProperties.get(path);
128155
if (pathItemProperties != null) {
129-
resolveString(pathItem::setDescription, pathItemProperties::getDescription);
130-
resolveString(pathItem::setSummary, pathItemProperties::getSummary);
131-
List<Operation> operations = pathItem.readOperations();
132-
List<Operation> operationsProperties = pathItemProperties.readOperations();
133-
for (int i = 0; i < operations.size(); i++) {
134-
Operation operation = operations.get(i);
135-
Operation operationProperties = operationsProperties.get(i);
136-
resolveString(operation::setDescription, operationProperties::getDescription);
137-
resolveString(operation::setSummary, operationProperties::getSummary);
138-
}
156+
resolveString(pathItem::description, pathItemProperties::getDescription);
157+
resolveString(pathItem::summary, pathItemProperties::getSummary);
158+
159+
Map<HttpMethod, Operation> operationMap = pathItem.readOperationsMap();
160+
Map<HttpMethod, Operation> operationMapProperties = pathItemProperties.readOperationsMap();
161+
162+
operationMapProperties.forEach((httpMethod, operationProperties) -> {
163+
Operation operationToCustomize = operationMap.get(httpMethod);
164+
if (operationToCustomize != null) {
165+
resolveString(operationToCustomize::description, operationProperties::getDescription);
166+
resolveString(operationToCustomize::summary, operationProperties::getSummary);
167+
resolveSet(operationToCustomize::tags, operationProperties::getTags);
168+
}
169+
});
139170
}});
140171
}
141172
}
142-
173+
174+
/**
175+
* Customize components.
176+
*
177+
* @param openApi the open api
178+
* @param componentsProperties the components properties
179+
*/
143180
private void customizeComponents(OpenAPI openApi, Components componentsProperties) {
144181
Components components = openApi.getComponents();
145182
if (components == null || CollectionUtils.isEmpty(components.getSchemas())) {
@@ -158,44 +195,52 @@ private void customizeComponents(OpenAPI openApi, Components componentsPropertie
158195
properties.forEach((propKey, propSchema) -> {
159196
Schema propSchemaProperties = (Schema) schemaProperties.getProperties().get(propKey);
160197
if (propSchemaProperties != null) {
161-
resolveString(propSchema::setDescription, propSchemaProperties::getDescription);
162-
resolveString(propSchema::setExample, propSchemaProperties::getExample);
198+
resolveString(propSchema::description, propSchemaProperties::getDescription);
199+
resolveString(propSchema::title, propSchemaProperties::getTitle);
200+
resolveString(propSchema::example, propSchemaProperties::getExample);
163201
}
164202
});
165203
}
166204
});
167205
}
168206
}
169207

208+
/**
209+
* Customize info.
210+
*
211+
* @param openApi the open api
212+
* @param infoProperties the info properties
213+
*/
170214
private void customizeInfo(OpenAPI openApi, Info infoProperties) {
171215
Info info = openApi.getInfo();
172216
if (info != null) {
173217
resolveString(info::title, infoProperties::getTitle);
174218
resolveString(info::description, infoProperties::getDescription);
175219
resolveString(info::version, infoProperties::getVersion);
176220
resolveString(info::termsOfService, infoProperties::getTermsOfService);
177-
}
178-
else
179-
openApi.info(infoProperties);
221+
resolveString(info::summary, infoProperties::getSummary);
180222

181-
License license = info.getLicense();
182-
License licenseProperties = infoProperties.getLicense();
183-
if (license != null) {
184-
resolveString(license::name, licenseProperties::getName);
185-
resolveString(license::url, licenseProperties::getUrl);
186-
}
187-
else
188-
info.license(licenseProperties);
189-
190-
Contact contact = info.getContact();
191-
Contact contactProperties = infoProperties.getContact();
192-
if (contact != null) {
193-
resolveString(contact::name, contactProperties::getName);
194-
resolveString(contact::email, contactProperties::getEmail);
195-
resolveString(contact::url, contactProperties::getUrl);
223+
License license = info.getLicense();
224+
License licenseProperties = infoProperties.getLicense();
225+
if (license != null) {
226+
resolveString(license::name, licenseProperties::getName);
227+
resolveString(license::url, licenseProperties::getUrl);
228+
}
229+
else
230+
info.license(licenseProperties);
231+
232+
Contact contact = info.getContact();
233+
Contact contactProperties = infoProperties.getContact();
234+
if (contact != null) {
235+
resolveString(contact::name, contactProperties::getName);
236+
resolveString(contact::email, contactProperties::getEmail);
237+
resolveString(contact::url, contactProperties::getUrl);
238+
}
239+
else
240+
info.contact(contactProperties);
196241
}
197242
else
198-
info.contact(contactProperties);
243+
openApi.info(infoProperties);
199244
}
200245

201246

@@ -212,4 +257,18 @@ private void resolveString(Consumer<String> setter, Supplier<Object> getter) {
212257
}
213258
}
214259

260+
/**
261+
* Resolve set.
262+
*
263+
* @param setter the setter
264+
* @param getter the getter
265+
*/
266+
private void resolveSet(Consumer<List> setter, Supplier<List> getter) {
267+
List value = getter.get();
268+
if (!CollectionUtils.isEmpty(value)) {
269+
setter.accept(value);
270+
}
271+
}
272+
273+
215274
}

Diff for: springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app212/HelloController.java

+22-4
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,33 @@
1818

1919
package test.org.springdoc.api.v30.app212;
2020

21+
import test.org.springdoc.api.v30.app217.PersonDTO;
22+
2123
import org.springframework.web.bind.annotation.GetMapping;
24+
import org.springframework.web.bind.annotation.PostMapping;
2225
import org.springframework.web.bind.annotation.RestController;
2326

2427
@RestController
2528
public class HelloController {
2629

27-
@GetMapping(value = "/persons")
28-
public PersonDTO persons() {
29-
return new PersonDTO("John");
30-
}
30+
@GetMapping(value = "/persons1")
31+
public PersonDTO persons1() {
32+
return new PersonDTO("John");
33+
}
34+
35+
@GetMapping(value = "/persons2")
36+
public PersonDTO persons2() {
37+
return new PersonDTO("John");
38+
}
39+
40+
@GetMapping(value = "/persons3")
41+
public PersonDTO persons3() {
42+
return new PersonDTO("John");
43+
}
44+
45+
@PostMapping(value = "/persons3")
46+
public PersonDTO persons33() {
47+
return new PersonDTO("John");
48+
}
3149

3250
}

Diff for: springdoc-openapi-starter-webmvc-api/src/test/resources/application-212.yml

+10-8
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,18 @@ springdoc:
1313
description: Description for 'name' property
1414
example: Example value for 'name' property
1515
paths:
16-
/persons:
16+
/persons3:
17+
post:
18+
tags:
19+
- hello
20+
summary: Summary of Post operationId 'persons'
21+
description: Description of Post operationId 'persons'
1722
get:
1823
tags:
19-
- hello-controller
20-
operationId: persons
21-
summary: Summary of operationId 'persons'
22-
description: Description of operationId 'persons'
24+
- hello
25+
summary: Summary of Get operationId 'persons'
26+
description: Description of Get operationId 'persons'
27+
2328
group-configs:
2429
- group: apiGroupName
2530
open-api:
@@ -39,9 +44,6 @@ springdoc:
3944
paths:
4045
/persons:
4146
get:
42-
tags:
43-
- hello-controller
44-
operationId: persons
4547
summary: Summary of operationId 'persons' in ApiGroupName
4648
description: Description of operationId 'persons' in ApiGroupName
4749

Diff for: springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app212-grouped.json

+65-5
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,74 @@
1212
}
1313
],
1414
"paths": {
15-
"/persons": {
15+
"/persons3": {
16+
"get": {
17+
"tags": [
18+
"hello"
19+
],
20+
"summary": "Summary of Get operationId 'persons'",
21+
"description": "Description of Get operationId 'persons'",
22+
"operationId": "persons3",
23+
"responses": {
24+
"200": {
25+
"description": "OK",
26+
"content": {
27+
"*/*": {
28+
"schema": {
29+
"$ref": "#/components/schemas/PersonDTO"
30+
}
31+
}
32+
}
33+
}
34+
}
35+
},
36+
"post": {
37+
"tags": [
38+
"hello"
39+
],
40+
"summary": "Summary of Post operationId 'persons'",
41+
"description": "Description of Post operationId 'persons'",
42+
"operationId": "persons33",
43+
"responses": {
44+
"200": {
45+
"description": "OK",
46+
"content": {
47+
"*/*": {
48+
"schema": {
49+
"$ref": "#/components/schemas/PersonDTO"
50+
}
51+
}
52+
}
53+
}
54+
}
55+
}
56+
},
57+
"/persons2": {
58+
"get": {
59+
"tags": [
60+
"hello-controller"
61+
],
62+
"operationId": "persons2",
63+
"responses": {
64+
"200": {
65+
"description": "OK",
66+
"content": {
67+
"*/*": {
68+
"schema": {
69+
"$ref": "#/components/schemas/PersonDTO"
70+
}
71+
}
72+
}
73+
}
74+
}
75+
}
76+
},
77+
"/persons1": {
1678
"get": {
1779
"tags": [
1880
"hello-controller"
1981
],
20-
"summary": "Summary of operationId 'persons' in ApiGroupName",
21-
"description": "Description of operationId 'persons' in ApiGroupName",
22-
"operationId": "persons",
82+
"operationId": "persons1",
2383
"responses": {
2484
"200": {
2585
"description": "OK",
@@ -50,4 +110,4 @@
50110
}
51111
}
52112
}
53-
}
113+
}

0 commit comments

Comments
 (0)