Skip to content

Commit

Permalink
Merge branch 'trim-indent-apply-schema' of https://github.com/e-build…
Browse files Browse the repository at this point in the history
…/springdoc-openapi into e-build-trim-indent-apply-schema
  • Loading branch information
bnasslahsen committed Sep 15, 2024
2 parents b7777e4 + 73a1904 commit b07e360
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import io.swagger.v3.oas.models.PathItem.HttpMethod;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.SpecVersion;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.responses.ApiResponses;
Expand Down Expand Up @@ -100,6 +101,7 @@
import org.springdoc.core.service.GenericResponseService;
import org.springdoc.core.service.OpenAPIService;
import org.springdoc.core.service.OperationService;
import org.springdoc.core.utils.PropertyResolverUtils;
import org.springdoc.core.utils.SpringDocUtils;

import org.springframework.aop.support.AopUtils;
Expand Down Expand Up @@ -352,6 +354,9 @@ protected OpenAPI getOpenApi(Locale locale) {
}
getPaths(mappingsMap, finalLocale, openAPI);

if (springDocConfigProperties.isTrimKotlinIndent())
this.trimIndent(openAPI);

Optional<CloudFunctionProvider> cloudFunctionProviderOptional = springDocProviders.getSpringCloudFunctionProvider();
cloudFunctionProviderOptional.ifPresent(cloudFunctionProvider -> {
List<RouterOperation> routerOperationList = cloudFunctionProvider.getRouterOperations(openAPI);
Expand Down Expand Up @@ -384,7 +389,6 @@ protected OpenAPI getOpenApi(Locale locale) {
if (!CollectionUtils.isEmpty(openAPI.getServers()) && !openAPI.getServers().equals(serversCopy))
openAPIService.setServersPresent(true);


openAPIService.setCachedOpenAPI(openAPI, finalLocale);

LOGGER.info("Init duration for springdoc-openapi is: {} ms",
Expand All @@ -396,12 +400,78 @@ protected OpenAPI getOpenApi(Locale locale) {
openAPIService.updateServers(openAPI);
}
openAPIService.updateServers(openAPI);
return openAPI; }
finally {
return openAPI;
} finally {
this.reentrantLock.unlock();
}
}

/**
* Indents are removed for properties that are mainly used as “explanations” using Open API.
* @param openAPI the open api
*/
private void trimIndent(OpenAPI openAPI) {
trimComponents(openAPI);
trimPaths(openAPI);
}

/**
* Trim the indent for descriptions in the 'components' of open api.
* @param openAPI the open api
*/
private void trimComponents(OpenAPI openAPI) {
final PropertyResolverUtils propertyResolverUtils = operationParser.getPropertyResolverUtils();
if (openAPI.getComponents() == null || openAPI.getComponents().getSchemas() == null) {
return;
}
for (Schema<?> schema : openAPI.getComponents().getSchemas().values()) {
schema.description(propertyResolverUtils.trimIndent(schema.getDescription()));
if (schema.getProperties() == null) {
continue;
}
for (Object prop : schema.getProperties().values()) {
if (prop instanceof Schema<?> schemaProp) {
schemaProp.setDescription(propertyResolverUtils.trimIndent(schemaProp.getDescription()));
}
}
}
}

/**
* Trim the indent for descriptions in the 'paths' of open api.
* @param openAPI the open api
*/
private void trimPaths(OpenAPI openAPI) {
final PropertyResolverUtils propertyResolverUtils = operationParser.getPropertyResolverUtils();
if (openAPI.getPaths() == null) {
return;
}
for (PathItem value : openAPI.getPaths().values()) {
value.setDescription(propertyResolverUtils.trimIndent(value.getDescription()));
trimIndentOperation(value.getGet());
trimIndentOperation(value.getPut());
trimIndentOperation(value.getPost());
trimIndentOperation(value.getDelete());
trimIndentOperation(value.getOptions());
trimIndentOperation(value.getHead());
trimIndentOperation(value.getPatch());
trimIndentOperation(value.getTrace());
}
}

/**
* Trim the indent for 'operation'
* @param operation the operation
*/
private void trimIndentOperation(Operation operation) {
final PropertyResolverUtils propertyResolverUtils = operationParser.getPropertyResolverUtils();
if (operation == null) {
return;
}
operation.setSummary(propertyResolverUtils.trimIndent(operation.getSummary()));
operation.setDescription(propertyResolverUtils.trimIndent(operation.getDescription()));
}

/**
* Gets paths.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -646,4 +646,12 @@ public Operation mergeOperation(Operation operation, Operation operationModel) {
public JavadocProvider getJavadocProvider() {
return parameterBuilder.getJavadocProvider();
}

/**
* Gets propertyResolverUtils
* @return propertyResolverUtils
*/
public PropertyResolverUtils getPropertyResolverUtils(){
return parameterBuilder.getPropertyResolverUtils();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,6 @@ public String resolve(String parameterProperty, Locale locale) {
}
if (parameterProperty.equals(result))
try {
if (springDocConfigProperties.isTrimKotlinIndent()) {
parameterProperty = trimIndent(parameterProperty);
}
result = factory.resolveEmbeddedValue(parameterProperty);
}
catch (IllegalArgumentException ex) {
Expand All @@ -119,18 +116,23 @@ public String resolve(String parameterProperty, Locale locale) {
* @param text The original string with possible leading indentation.
* @return The string with leading indentation removed from each line.
*/
private String trimIndent(String text) {
if (text == null) {
return null;
public String trimIndent(String text) {
try {
if (text == null) {
return null;
}
final String newLine = "\n";
String[] lines = text.split(newLine);
int minIndent = resolveMinIndent(lines);
return Arrays.stream(lines)
.map(line -> line.substring(Math.min(line.length(), minIndent)))
.reduce((a, b) -> a + newLine + b)
.orElse(StringUtils.EMPTY);
} catch (Exception ex){
LOGGER.warn(ex.getMessage());
return text;
}
final String newLine = "\n";
String[] lines = text.split(newLine);
int minIndent = resolveMinIndent(lines);
return Arrays.stream(lines)
.map(line -> line.substring(Math.min(line.length(), minIndent)))
.reduce((a, b) -> a + newLine + b)
.orElse(StringUtils.EMPTY);
}
}

private int resolveMinIndent(String[] lines) {
return Arrays.stream(lines)
Expand Down Expand Up @@ -222,4 +224,4 @@ public Map<String, Object> resolveExtensions(Locale locale, Map<String, Object>
else
return extensions;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package test.org.springdoc.api.app11

import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

Expand All @@ -20,11 +22,75 @@ class ExampleController {
| 400 | STORE_NOT_FOUND |Store not found. | | |
"""
)
@GetMapping("/foo/remove-kotlin-indent")
@GetMapping("/foo/trim-kotlin-indent")
fun readFoo(@RequestParam name: String?) = FooResponse("Hello ${name ?: "world"}")

}

data class FooResponse(
private val name: String,
)
val name: String,
)

@RestController
class ExampleController2 {

@GetMapping("/foo/trim-kotlin-indent/schema")
fun readFoo(
@RequestBody request: FooRequestWithSchema,
) = FooResponseWithSchema(
name = "Hello ${request.age ?: "world"}",
subFoo = SubFooResponseWithSchema(subName = "sub foo name"),
)
}

@Schema(
name = "foo request",
description = """
foo request class description
with kotlin indent
"""
)
data class FooRequestWithSchema(
@Schema(
name = "age",
description = """
foo request field with kotlin indent
"""
)
val age: Int,
)

@Schema(
name = "foo response",
description = """
foo response class description
with kotlin indent
"""
)
data class FooResponseWithSchema(
@Schema(
name = "name",
description = """
foo response fields with kotlin indent
"""
)
val name: String,
val subFoo: SubFooResponseWithSchema
)

@Schema(
name = "sub foo response",
description = """
sub foo response class description
with kotlin indent
"""
)
data class SubFooResponseWithSchema(
@Schema(
name = "subName",
description = """
sub foo response fields with kotlin indent
"""
)
val subName: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
}
],
"paths": {
"/foo/remove-kotlin-indent": {
"/foo/trim-kotlin-indent": {
"get": {
"tags": [
"example-controller"
Expand Down Expand Up @@ -42,18 +42,94 @@
}
}
}
},
"/foo/trim-kotlin-indent/schema": {
"get": {
"tags": [
"example-controller-2"
],
"operationId": "readFoo_1",
"parameters": [
{
"name": "request",
"in": "query",
"required": true,
"schema": {
"$ref": "#/components/schemas/foo request"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/foo response"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"FooResponse": {
"required": [
"name"
],
"type": "object",
"properties": {
"name": {
"type": "string",
"writeOnly": true
"type": "string"
}
}
},
"foo request": {
"required": [
"age"
],
"type": "object",
"properties": {
"age": {
"type": "integer",
"description": "\nfoo request field with kotlin indent\n",
"format": "int32"
}
},
"description": "\nfoo request class description\nwith kotlin indent\n"
},
"foo response": {
"required": [
"name",
"subFoo"
],
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "\nfoo response fields with kotlin indent\n"
},
"subFoo": {
"$ref": "#/components/schemas/sub foo response"
}
},
"description": "\nfoo response class description\nwith kotlin indent\n"
},
"sub foo response": {
"required": [
"subName"
],
"type": "object",
"properties": {
"subName": {
"type": "string",
"description": "\nsub foo response fields with kotlin indent\n"
}
},
"description": "\nsub foo response class description\nwith kotlin indent\n"
}
}
}
Expand Down

0 comments on commit b07e360

Please sign in to comment.