Skip to content

Commit 037f5ec

Browse files
author
Thomas Deville-Duc
committed
add property resolver on @Schema.description
1 parent 7452898 commit 037f5ec

File tree

8 files changed

+199
-46
lines changed

8 files changed

+199
-46
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,19 @@
1818

1919
package org.springdoc.api;
2020

21-
import java.io.UnsupportedEncodingException;
22-
import java.lang.reflect.Method;
23-
import java.net.URLDecoder;
24-
import java.nio.charset.StandardCharsets;
25-
import java.time.Duration;
26-
import java.time.Instant;
27-
import java.util.ArrayList;
28-
import java.util.Arrays;
29-
import java.util.HashSet;
30-
import java.util.List;
31-
import java.util.Map;
32-
import java.util.Objects;
33-
import java.util.Optional;
34-
import java.util.Set;
35-
import java.util.stream.Collectors;
36-
3721
import com.fasterxml.jackson.annotation.JsonView;
3822
import io.swagger.v3.core.filter.SpecFilter;
3923
import io.swagger.v3.core.util.ReflectionUtils;
4024
import io.swagger.v3.oas.annotations.Hidden;
41-
import io.swagger.v3.oas.models.Components;
42-
import io.swagger.v3.oas.models.OpenAPI;
43-
import io.swagger.v3.oas.models.Operation;
44-
import io.swagger.v3.oas.models.PathItem;
25+
import io.swagger.v3.oas.models.*;
4526
import io.swagger.v3.oas.models.PathItem.HttpMethod;
46-
import io.swagger.v3.oas.models.Paths;
27+
import io.swagger.v3.oas.models.media.Schema;
4728
import io.swagger.v3.oas.models.responses.ApiResponses;
4829
import org.slf4j.Logger;
4930
import org.slf4j.LoggerFactory;
50-
import org.springdoc.core.AbstractRequestBuilder;
51-
import org.springdoc.core.GenericResponseBuilder;
52-
import org.springdoc.core.MethodAttributes;
53-
import org.springdoc.core.OpenAPIBuilder;
54-
import org.springdoc.core.OperationBuilder;
55-
import org.springdoc.core.SpringDocConfigProperties;
31+
import org.springdoc.core.*;
5632
import org.springdoc.core.SpringDocConfigProperties.GroupConfig;
5733
import org.springdoc.core.customizers.OpenApiCustomiser;
58-
5934
import org.springframework.core.annotation.AnnotatedElementUtils;
6035
import org.springframework.core.annotation.AnnotationUtils;
6136
import org.springframework.util.AntPathMatcher;
@@ -65,6 +40,15 @@
6540
import org.springframework.web.bind.annotation.RequestMethod;
6641
import org.springframework.web.method.HandlerMethod;
6742

43+
import java.io.UnsupportedEncodingException;
44+
import java.lang.reflect.Method;
45+
import java.net.URLDecoder;
46+
import java.nio.charset.StandardCharsets;
47+
import java.time.Duration;
48+
import java.time.Instant;
49+
import java.util.*;
50+
import java.util.stream.Collectors;
51+
6852
public abstract class AbstractOpenApiResource extends SpecFilter {
6953

7054
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOpenApiResource.class);
@@ -128,8 +112,12 @@ protected synchronized OpenAPI getOpenApi() {
128112
getPaths(mappingsMap);
129113
openApi = openAPIBuilder.getCalculatedOpenAPI();
130114

115+
131116
// run the optional customisers
132117
openApiCustomisers.ifPresent(apiCustomisers -> apiCustomisers.forEach(openApiCustomiser -> openApiCustomiser.customise(openApi)));
118+
119+
getModelSchemas(openAPIBuilder);
120+
133121
computeDone = true;
134122
if (springDocConfigProperties.isRemoveBrokenReferenceDefinitions())
135123
this.removeBrokenReferenceDefinitions(openApi);
@@ -146,6 +134,21 @@ protected synchronized OpenAPI getOpenApi() {
146134
return openApi;
147135
}
148136

137+
protected void getModelSchemas(OpenAPIBuilder openAPIBuilder) {
138+
Components components = openAPIBuilder.getComponents();
139+
140+
if (components != null) {
141+
Map<String, Schema> mapSchemas = components.getSchemas();
142+
if (!CollectionUtils.isEmpty(mapSchemas)) {
143+
Map<String, Schema> resolvedSchemas = mapSchemas.entrySet().stream().map(es -> {
144+
es.setValue(openAPIBuilder.resolveProperties(es.getValue()));
145+
return es;
146+
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
147+
openAPIBuilder.getComponents().setSchemas(resolvedSchemas);
148+
}
149+
}
150+
}
151+
149152
protected abstract void getPaths(Map<String, Object> findRestControllers);
150153

151154
protected void calculatePath(HandlerMethod handlerMethod, String operationPath,

springdoc-openapi-common/src/main/java/org/springdoc/core/OpenAPIBuilder.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,6 @@
1818

1919
package org.springdoc.core;
2020

21-
import java.util.ArrayList;
22-
import java.util.Collections;
23-
import java.util.HashMap;
24-
import java.util.HashSet;
25-
import java.util.List;
26-
import java.util.Locale;
27-
import java.util.Map;
28-
import java.util.Optional;
29-
import java.util.Set;
30-
import java.util.function.Consumer;
31-
import java.util.function.Supplier;
32-
import java.util.stream.Collectors;
33-
import java.util.stream.Stream;
34-
3521
import io.swagger.v3.core.util.AnnotationsUtils;
3622
import io.swagger.v3.oas.annotations.Hidden;
3723
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
@@ -44,13 +30,13 @@
4430
import io.swagger.v3.oas.models.info.Contact;
4531
import io.swagger.v3.oas.models.info.Info;
4632
import io.swagger.v3.oas.models.info.License;
33+
import io.swagger.v3.oas.models.media.Schema;
4734
import io.swagger.v3.oas.models.security.SecurityScheme;
4835
import io.swagger.v3.oas.models.servers.Server;
4936
import org.apache.commons.lang3.StringUtils;
5037
import org.slf4j.Logger;
5138
import org.slf4j.LoggerFactory;
5239
import org.springdoc.core.customizers.OpenApiBuilderCustomiser;
53-
5440
import org.springframework.beans.factory.config.BeanDefinition;
5541
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
5642
import org.springframework.context.ApplicationContext;
@@ -65,9 +51,13 @@
6551
import org.springframework.web.bind.annotation.RestController;
6652
import org.springframework.web.method.HandlerMethod;
6753

68-
import static org.springdoc.core.Constants.DEFAULT_SERVER_DESCRIPTION;
69-
import static org.springdoc.core.Constants.DEFAULT_TITLE;
70-
import static org.springdoc.core.Constants.DEFAULT_VERSION;
54+
import java.util.*;
55+
import java.util.function.Consumer;
56+
import java.util.function.Supplier;
57+
import java.util.stream.Collectors;
58+
import java.util.stream.Stream;
59+
60+
import static org.springdoc.core.Constants.*;
7161

7262
public class OpenAPIBuilder {
7363

@@ -319,6 +309,25 @@ private Info resolveProperties(Info info) {
319309
return info;
320310
}
321311

312+
public Schema resolveProperties(Schema schema) {
313+
PropertyResolverUtils propertyResolverUtils = context.getBean(PropertyResolverUtils.class);
314+
resolveProperty(schema::getName, schema::name, propertyResolverUtils);
315+
resolveProperty(schema::getTitle, schema::title, propertyResolverUtils);
316+
resolveProperty(schema::getDescription, schema::description, propertyResolverUtils);
317+
318+
Map<String, Schema> properties = schema.getProperties();
319+
if (!CollectionUtils.isEmpty(properties)) {
320+
Map<String, Schema> resolvedSchemas = properties.entrySet().stream().map(es -> {
321+
es.setValue(resolveProperties(es.getValue()));
322+
return es;
323+
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
324+
schema.setProperties(resolvedSchemas);
325+
}
326+
327+
return schema;
328+
}
329+
330+
322331
private void resolveProperty(Supplier<String> getProperty, Consumer<String> setProperty,
323332
PropertyResolverUtils propertyResolverUtils) {
324333
String value = getProperty.get();

springdoc-openapi-data-rest/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
<artifactId>springdoc-openapi-data-rest</artifactId>
1111
<dependencies>
12+
<dependency>
13+
<groupId>jakarta.annotation</groupId>
14+
<artifactId>jakarta.annotation-api</artifactId>
15+
</dependency>
1216
<!-- springdoc-common -->
1317
<dependency>
1418
<groupId>org.springdoc</groupId>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package test.org.springdoc.api.app101;
2+
3+
import io.swagger.v3.oas.annotations.media.Content;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
@RestController
11+
@RequestMapping("/hello")
12+
public class HelloController {
13+
14+
@GetMapping
15+
@ApiResponse(content = @Content(schema = @Schema(
16+
description = "${test.app101.operation.hello.response.schema.description}",
17+
implementation = HelloDTO.class)))
18+
public HelloDTO hello() {
19+
return new HelloDTO();
20+
}
21+
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package test.org.springdoc.api.app101;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
@Schema(description = "${test.app101.schema.hello.description}")
7+
public class HelloDTO {
8+
9+
@Schema(description = "${test.app101.schema.hello.param.id.description}")
10+
private String id;
11+
12+
@JsonProperty("id")
13+
public String getId() {
14+
return id;
15+
}
16+
17+
public void setId(String id) {
18+
this.id = id;
19+
}
20+
21+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 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.app101;
20+
21+
22+
import org.springframework.boot.autoconfigure.SpringBootApplication;
23+
import org.springframework.test.context.ActiveProfiles;
24+
import test.org.springdoc.api.AbstractSpringDocTest;
25+
26+
@ActiveProfiles("101")
27+
public class SpringDocApp101Test extends AbstractSpringDocTest {
28+
29+
@SpringBootApplication
30+
static class SpringDocTestApp {}
31+
32+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
test:
2+
app100:
3+
operation:
4+
hello:
5+
response:
6+
schema:
7+
description: Description of schema of api response hello
8+
schema:
9+
hello:
10+
description: Description of schema of hello entity
11+
param:
12+
id:
13+
description: Description of schema of param id for api hello
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
"paths": {
14+
"/hello": {
15+
"get": {
16+
"tags": [
17+
"hello-controller"
18+
],
19+
"operationId": "hello",
20+
"responses": {
21+
"default": {
22+
"description": "default response",
23+
"content": {
24+
"*/*": {
25+
"schema": {
26+
"$ref": "#/components/schemas/HelloDTO"
27+
}
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
},
35+
"components": {
36+
"schemas": {
37+
"HelloDTO": {
38+
"type": "object",
39+
"properties": {
40+
"id": {
41+
"type": "string",
42+
"description": "Description of schema of param id for api hello"
43+
}
44+
},
45+
"description": "Description of schema of hello entity"
46+
}
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)