Skip to content

Commit

Permalink
Improve support for externalizing strings in generated openapi schema…
Browse files Browse the repository at this point in the history
… via… #2418
  • Loading branch information
bnasslahsen committed Mar 31, 2024
1 parent 1a9c257 commit 460d543
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 55 deletions.
Expand Up @@ -33,6 +33,7 @@
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.PathItem.HttpMethod;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
Expand Down Expand Up @@ -84,12 +85,25 @@
*/
public class SpecPropertiesCustomizer implements GlobalOpenApiCustomizer {

/**
* The Open api properties.
*/
private final OpenAPI openApiProperties;

/**
* Instantiates a new Spec properties customizer.
*
* @param springDocConfigProperties the spring doc config properties
*/
public SpecPropertiesCustomizer(SpringDocConfigProperties springDocConfigProperties) {
this.openApiProperties = springDocConfigProperties.getOpenApi();
}

/**
* Instantiates a new Spec properties customizer.
*
* @param openApiProperties the open api properties
*/
public SpecPropertiesCustomizer(OpenAPI openApiProperties) {
this.openApiProperties = openApiProperties;
}
Expand All @@ -99,6 +113,12 @@ public void customise(OpenAPI openApi) {
customizeOpenApi(openApi, openApiProperties);
}

/**
* Customize open api.
*
* @param openApi the open api
* @param openApiProperties the open api properties
*/
private void customizeOpenApi(OpenAPI openApi, OpenAPI openApiProperties) {
if (openApiProperties != null) {
Info infoProperties = openApiProperties.getInfo();
Expand All @@ -108,12 +128,19 @@ private void customizeOpenApi(OpenAPI openApi, OpenAPI openApiProperties) {
Components componentsProperties = openApiProperties.getComponents();
if (componentsProperties != null)
customizeComponents(openApi, componentsProperties);

Paths pathsProperties = openApiProperties.getPaths();
if (pathsProperties != null)
customizePaths(openApi, pathsProperties);
}
}

/**
* Customize paths.
*
* @param openApi the open api
* @param pathsProperties the paths properties
*/
private void customizePaths(OpenAPI openApi, Paths pathsProperties) {
Paths paths = openApi.getPaths();
if (paths == null) {
Expand All @@ -126,20 +153,30 @@ private void customizePaths(OpenAPI openApi, Paths pathsProperties) {
}
PathItem pathItemProperties = pathsProperties.get(path);
if (pathItemProperties != null) {
resolveString(pathItem::setDescription, pathItemProperties::getDescription);
resolveString(pathItem::setSummary, pathItemProperties::getSummary);
List<Operation> operations = pathItem.readOperations();
List<Operation> operationsProperties = pathItemProperties.readOperations();
for (int i = 0; i < operations.size(); i++) {
Operation operation = operations.get(i);
Operation operationProperties = operationsProperties.get(i);
resolveString(operation::setDescription, operationProperties::getDescription);
resolveString(operation::setSummary, operationProperties::getSummary);
}
resolveString(pathItem::description, pathItemProperties::getDescription);
resolveString(pathItem::summary, pathItemProperties::getSummary);

Map<HttpMethod, Operation> operationMap = pathItem.readOperationsMap();
Map<HttpMethod, Operation> operationMapProperties = pathItemProperties.readOperationsMap();

operationMapProperties.forEach((httpMethod, operationProperties) -> {
Operation operationToCustomize = operationMap.get(httpMethod);
if (operationToCustomize != null) {
resolveString(operationToCustomize::description, operationProperties::getDescription);
resolveString(operationToCustomize::summary, operationProperties::getSummary);
resolveSet(operationToCustomize::tags, operationProperties::getTags);
}
});
}});
}
}


/**
* Customize components.
*
* @param openApi the open api
* @param componentsProperties the components properties
*/
private void customizeComponents(OpenAPI openApi, Components componentsProperties) {
Components components = openApi.getComponents();
if (components == null || CollectionUtils.isEmpty(components.getSchemas())) {
Expand All @@ -158,44 +195,52 @@ private void customizeComponents(OpenAPI openApi, Components componentsPropertie
properties.forEach((propKey, propSchema) -> {
Schema propSchemaProperties = (Schema) schemaProperties.getProperties().get(propKey);
if (propSchemaProperties != null) {
resolveString(propSchema::setDescription, propSchemaProperties::getDescription);
resolveString(propSchema::setExample, propSchemaProperties::getExample);
resolveString(propSchema::description, propSchemaProperties::getDescription);
resolveString(propSchema::title, propSchemaProperties::getTitle);
resolveString(propSchema::example, propSchemaProperties::getExample);
}
});
}
});
}
}

/**
* Customize info.
*
* @param openApi the open api
* @param infoProperties the info properties
*/
private void customizeInfo(OpenAPI openApi, Info infoProperties) {
Info info = openApi.getInfo();
if (info != null) {
resolveString(info::title, infoProperties::getTitle);
resolveString(info::description, infoProperties::getDescription);
resolveString(info::version, infoProperties::getVersion);
resolveString(info::termsOfService, infoProperties::getTermsOfService);
}
else
openApi.info(infoProperties);
resolveString(info::summary, infoProperties::getSummary);

License license = info.getLicense();
License licenseProperties = infoProperties.getLicense();
if (license != null) {
resolveString(license::name, licenseProperties::getName);
resolveString(license::url, licenseProperties::getUrl);
}
else
info.license(licenseProperties);

Contact contact = info.getContact();
Contact contactProperties = infoProperties.getContact();
if (contact != null) {
resolveString(contact::name, contactProperties::getName);
resolveString(contact::email, contactProperties::getEmail);
resolveString(contact::url, contactProperties::getUrl);
License license = info.getLicense();
License licenseProperties = infoProperties.getLicense();
if (license != null) {
resolveString(license::name, licenseProperties::getName);
resolveString(license::url, licenseProperties::getUrl);
}
else
info.license(licenseProperties);

Contact contact = info.getContact();
Contact contactProperties = infoProperties.getContact();
if (contact != null) {
resolveString(contact::name, contactProperties::getName);
resolveString(contact::email, contactProperties::getEmail);
resolveString(contact::url, contactProperties::getUrl);
}
else
info.contact(contactProperties);
}
else
info.contact(contactProperties);
openApi.info(infoProperties);
}


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

/**
* Resolve set.
*
* @param setter the setter
* @param getter the getter
*/
private void resolveSet(Consumer<List> setter, Supplier<List> getter) {
List value = getter.get();
if (!CollectionUtils.isEmpty(value)) {
setter.accept(value);
}
}


}
Expand Up @@ -18,15 +18,33 @@

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

import test.org.springdoc.api.v30.app217.PersonDTO;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

@GetMapping(value = "/persons")
public PersonDTO persons() {
return new PersonDTO("John");
}
@GetMapping(value = "/persons1")
public PersonDTO persons1() {
return new PersonDTO("John");
}

@GetMapping(value = "/persons2")
public PersonDTO persons2() {
return new PersonDTO("John");
}

@GetMapping(value = "/persons3")
public PersonDTO persons3() {
return new PersonDTO("John");
}

@PostMapping(value = "/persons3")
public PersonDTO persons33() {
return new PersonDTO("John");
}

}
Expand Up @@ -13,13 +13,18 @@ springdoc:
description: Description for 'name' property
example: Example value for 'name' property
paths:
/persons:
/persons3:
post:
tags:
- hello
summary: Summary of Post operationId 'persons'
description: Description of Post operationId 'persons'
get:
tags:
- hello-controller
operationId: persons
summary: Summary of operationId 'persons'
description: Description of operationId 'persons'
- hello
summary: Summary of Get operationId 'persons'
description: Description of Get operationId 'persons'

group-configs:
- group: apiGroupName
open-api:
Expand All @@ -39,9 +44,6 @@ springdoc:
paths:
/persons:
get:
tags:
- hello-controller
operationId: persons
summary: Summary of operationId 'persons' in ApiGroupName
description: Description of operationId 'persons' in ApiGroupName

Expand Up @@ -12,14 +12,74 @@
}
],
"paths": {
"/persons": {
"/persons3": {
"get": {
"tags": [
"hello"
],
"summary": "Summary of Get operationId 'persons'",
"description": "Description of Get operationId 'persons'",
"operationId": "persons3",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/PersonDTO"
}
}
}
}
}
},
"post": {
"tags": [
"hello"
],
"summary": "Summary of Post operationId 'persons'",
"description": "Description of Post operationId 'persons'",
"operationId": "persons33",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/PersonDTO"
}
}
}
}
}
}
},
"/persons2": {
"get": {
"tags": [
"hello-controller"
],
"operationId": "persons2",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/PersonDTO"
}
}
}
}
}
}
},
"/persons1": {
"get": {
"tags": [
"hello-controller"
],
"summary": "Summary of operationId 'persons' in ApiGroupName",
"description": "Description of operationId 'persons' in ApiGroupName",
"operationId": "persons",
"operationId": "persons1",
"responses": {
"200": {
"description": "OK",
Expand Down Expand Up @@ -50,4 +110,4 @@
}
}
}
}
}

0 comments on commit 460d543

Please sign in to comment.