Skip to content

Commit 3c6a790

Browse files
author
bnasslahsen
committed
Add support to configure packages-to-scan as list using YAML Syntax. Fixes #376
1 parent 64ac49e commit 3c6a790

File tree

25 files changed

+384
-758
lines changed

25 files changed

+384
-758
lines changed

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

+27-34
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Arrays;
2828
import java.util.List;
2929
import java.util.Map;
30+
import java.util.Objects;
3031
import java.util.Optional;
3132
import java.util.Set;
3233
import java.util.stream.Collectors;
@@ -49,9 +50,10 @@
4950
import org.springdoc.core.MethodAttributes;
5051
import org.springdoc.core.OpenAPIBuilder;
5152
import org.springdoc.core.OperationBuilder;
53+
import org.springdoc.core.SpringDocConfigProperties;
54+
import org.springdoc.core.SpringDocConfigProperties.GroupConfig;
5255
import org.springdoc.core.customizers.OpenApiCustomiser;
5356

54-
import org.springframework.beans.factory.annotation.Value;
5557
import org.springframework.core.annotation.AnnotationUtils;
5658
import org.springframework.util.AntPathMatcher;
5759
import org.springframework.util.CollectionUtils;
@@ -60,10 +62,6 @@
6062
import org.springframework.web.bind.annotation.RequestMethod;
6163
import org.springframework.web.method.HandlerMethod;
6264

63-
import static org.springdoc.core.Constants.SPRINGDOC_CACHE_DISABLED_VALUE;
64-
import static org.springdoc.core.Constants.SPRINGDOC_PACKAGES_TO_SCAN;
65-
import static org.springdoc.core.Constants.SPRINGDOC_PATHS_TO_MATCH;
66-
6765
public abstract class AbstractOpenApiResource {
6866

6967
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOpenApiResource.class);
@@ -80,45 +78,28 @@ public abstract class AbstractOpenApiResource {
8078

8179
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
8280

83-
private boolean computeDone;
84-
85-
@Value(SPRINGDOC_PACKAGES_TO_SCAN)
86-
private List<String> packagesToScan;
81+
private final SpringDocConfigProperties springDocConfigProperties;
8782

88-
@Value(SPRINGDOC_PATHS_TO_MATCH)
89-
private List<String> pathsToMatch;
83+
private boolean computeDone;
9084

91-
@Value(SPRINGDOC_CACHE_DISABLED_VALUE)
92-
private boolean cacheDisabled;
85+
private final String groupName;
9386

94-
protected AbstractOpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder requestBuilder,
87+
protected AbstractOpenApiResource(String groupName, OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder requestBuilder,
9588
GenericResponseBuilder responseBuilder, OperationBuilder operationParser,
96-
Optional<List<OpenApiCustomiser>> openApiCustomisers) {
89+
Optional<List<OpenApiCustomiser>> openApiCustomisers, SpringDocConfigProperties springDocConfigProperties) {
9790
super();
91+
this.groupName = Objects.requireNonNull(groupName, "groupName");
9892
this.openAPIBuilder = openAPIBuilder;
9993
this.requestBuilder = requestBuilder;
10094
this.responseBuilder = responseBuilder;
10195
this.operationParser = operationParser;
10296
this.openApiCustomisers = openApiCustomisers;
103-
}
104-
105-
protected AbstractOpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder requestBuilder,
106-
GenericResponseBuilder responseBuilder, OperationBuilder operationParser,
107-
Optional<List<OpenApiCustomiser>> openApiCustomisers, List<String> pathsToMatch, List<String> packagesToScan, boolean cacheDisabled) {
108-
super();
109-
this.openAPIBuilder = openAPIBuilder;
110-
this.requestBuilder = requestBuilder;
111-
this.responseBuilder = responseBuilder;
112-
this.operationParser = operationParser;
113-
this.openApiCustomisers = openApiCustomisers;
114-
this.pathsToMatch = pathsToMatch;
115-
this.packagesToScan = packagesToScan;
116-
this.cacheDisabled = cacheDisabled;
97+
this.springDocConfigProperties = springDocConfigProperties;
11798
}
11899

119100
protected synchronized OpenAPI getOpenApi() {
120101
OpenAPI openApi;
121-
if (!computeDone || cacheDisabled) {
102+
if (!computeDone || Boolean.TRUE.equals(springDocConfigProperties.getCache().getDisabled())) {
122103
Instant start = Instant.now();
123104
openAPIBuilder.build();
124105
Map<String, Object> restControllersMap = openAPIBuilder.getRestControllersMap();
@@ -171,15 +152,15 @@ protected void calculatePath(OpenAPIBuilder openAPIBuilder, HandlerMethod handle
171152
continue;
172153
}
173154

174-
RequestMapping reqMappringClass = ReflectionUtils.getAnnotation(handlerMethod.getBeanType(),
155+
RequestMapping reqMappingClass = ReflectionUtils.getAnnotation(handlerMethod.getBeanType(),
175156
RequestMapping.class);
176157

177158
MethodAttributes methodAttributes = new MethodAttributes();
178159
methodAttributes.setMethodOverloaded(existingOperation != null);
179160

180-
if (reqMappringClass != null) {
181-
methodAttributes.setClassConsumes(reqMappringClass.consumes());
182-
methodAttributes.setClassProduces(reqMappringClass.produces());
161+
if (reqMappingClass != null) {
162+
methodAttributes.setClassConsumes(reqMappingClass.consumes());
163+
methodAttributes.setClassProduces(reqMappingClass.produces());
183164
}
184165

185166
methodAttributes.calculateConsumesProduces(method);
@@ -336,10 +317,22 @@ private PathItem buildPathItem(RequestMethod requestMethod, Operation operation,
336317
}
337318

338319
protected boolean isPackageToScan(String aPackage) {
320+
List<String> packagesToScan = springDocConfigProperties.getPackagesToScan();
321+
if (CollectionUtils.isEmpty(packagesToScan)) {
322+
Optional<GroupConfig> optionalGroupConfig = springDocConfigProperties.getGroupConfigs().stream().filter(groupConfig -> this.groupName.equals(groupConfig.getGroup())).findAny();
323+
if (optionalGroupConfig.isPresent())
324+
packagesToScan = optionalGroupConfig.get().getPackagesToScan();
325+
}
339326
return CollectionUtils.isEmpty(packagesToScan) || packagesToScan.stream().anyMatch(pack -> aPackage.equals(pack) || aPackage.startsWith(pack + "."));
340327
}
341328

342329
protected boolean isPathToMatch(String operationPath) {
330+
List<String> pathsToMatch = springDocConfigProperties.getPathsToMatch();
331+
if (CollectionUtils.isEmpty(pathsToMatch)) {
332+
Optional<GroupConfig> optionalGroupConfig = springDocConfigProperties.getGroupConfigs().stream().filter(groupConfig -> this.groupName.equals(groupConfig.getGroup())).findAny();
333+
if (optionalGroupConfig.isPresent())
334+
pathsToMatch = optionalGroupConfig.get().getPathsToMatch();
335+
}
343336
return CollectionUtils.isEmpty(pathsToMatch) || pathsToMatch.stream().anyMatch(pattern -> antPathMatcher.match(pattern, operationPath));
344337
}
345338

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestBuilder.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ else if (!RequestMethod.GET.equals(requestMethod)) {
186186
}
187187
}
188188

189+
LinkedHashMap<String, Parameter> map = getParameterLinkedHashMap(components, methodAttributes, operationParameters, parametersDocMap);
190+
191+
setParams(operation, new ArrayList(map.values()), requestBodyInfo);
192+
// allow for customisation
193+
operation = customiseOperation(operation, handlerMethod);
194+
195+
return operation;
196+
}
197+
198+
private LinkedHashMap<String, Parameter> getParameterLinkedHashMap(Components components, MethodAttributes methodAttributes, List<Parameter> operationParameters, Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap) {
189199
LinkedHashMap<String, Parameter> map = operationParameters.stream()
190200
.collect(Collectors.toMap(
191201
Parameter::getName,
@@ -204,12 +214,7 @@ else if (!RequestMethod.GET.equals(requestMethod)) {
204214
map.put(entry.getKey(), parameter);
205215
}
206216
}
207-
208-
setParams(operation, new ArrayList(map.values()), requestBodyInfo);
209-
// allow for customisation
210-
operation = customiseOperation(operation, handlerMethod);
211-
212-
return operation;
217+
return map;
213218
}
214219

215220
protected Operation customiseOperation(Operation operation, HandlerMethod handlerMethod) {

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/Constants.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ public final class Constants {
4040

4141
public static final String SPRINGDOC_CACHE_DISABLED = "springdoc.cache.disabled";
4242

43-
public static final String SPRINGDOC_CACHE_DISABLED_VALUE = "${" + SPRINGDOC_CACHE_DISABLED + ":false}";
44-
4543
public static final String SPRINGDOC_SWAGGER_UI_ENABLED = "springdoc.swagger-ui.enabled";
4644

4745
public static final String SPRINGDOC_SWAGGER_UI_CONFIG_URL = "springdoc.swagger-ui.configUrl";
@@ -60,10 +58,6 @@ public final class Constants {
6058

6159
public static final String SPRINGDOC_SHOW_ACTUATOR = "springdoc.show-actuator";
6260

63-
public static final String SPRINGDOC_PACKAGES_TO_SCAN = "${springdoc.packages-to-scan" + NULL + "}";
64-
65-
public static final String SPRINGDOC_PATHS_TO_MATCH = "${springdoc.paths-to-match" + NULL + "}";
66-
6761
public static final String SPRINGDOC_ACTUATOR_TAG = "Actuator";
6862

6963
public static final String SPRINGDOC_ACTUATOR_DESCRIPTION = "Monitor and interact";
@@ -90,6 +84,8 @@ public final class Constants {
9084

9185
public static final String MVC_SERVLET_PATH = "${spring.mvc.servlet.path" + NULL + "}";
9286

87+
public static final String DEFAULT_GROUP_NAME="springdocDefault";
88+
9389
public static final String GET_METHOD = "get";
9490

9591
public static final String POST_METHOD = "post";

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ else if (openAPI.getInfo() == null) {
141141
// default server value
142142
if (CollectionUtils.isEmpty(openAPI.getServers()) || !isServersPresent) {
143143
Server server = new Server().url(serverBaseUrl).description(DEFAULT_SERVER_DESCRIPTION);
144-
List servers = new ArrayList();
144+
List<Server> servers = new ArrayList();
145145
servers.add(server);
146146
openAPI.setServers(servers);
147147
}

Diff for: springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java

+78
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
package org.springdoc.core;
2020

21+
import java.util.ArrayList;
2122
import java.util.List;
2223

2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -41,6 +42,11 @@ public class SpringDocConfigProperties {
4142

4243
private List<String> pathsToMatch;
4344

45+
private Cache cache = new Cache();
46+
47+
private List<GroupConfig> groupConfigs = new ArrayList<>();
48+
49+
4450
public List<String> getPackagesToScan() {
4551
return packagesToScan;
4652
}
@@ -81,6 +87,14 @@ public void setPathsToMatch(List<String> pathsToMatch) {
8187
this.pathsToMatch = pathsToMatch;
8288
}
8389

90+
public Cache getCache() {
91+
return cache;
92+
}
93+
94+
public void setCache(Cache cache) {
95+
this.cache = cache;
96+
}
97+
8498
public static class Webjars {
8599
private String prefix = "/webjars";
86100

@@ -142,4 +156,68 @@ public void setEnabled(Boolean enabled) {
142156
this.enabled = enabled;
143157
}
144158
}
159+
160+
public static class Cache {
161+
private Boolean disabled = false;
162+
163+
public Boolean getDisabled() {
164+
return disabled;
165+
}
166+
167+
public void setDisabled(Boolean disabled) {
168+
this.disabled = disabled;
169+
}
170+
}
171+
172+
public List<GroupConfig> getGroupConfigs() {
173+
return groupConfigs;
174+
}
175+
176+
public void setGroupConfigs(List<GroupConfig> groupConfigs) {
177+
this.groupConfigs = groupConfigs;
178+
}
179+
180+
public void addGroupConfig(GroupConfig groupConfigs) {
181+
this.groupConfigs.add(groupConfigs);
182+
}
183+
184+
public static class GroupConfig {
185+
public GroupConfig() { }
186+
187+
public GroupConfig(String group, List<String> pathsToMatch, List<String> packagesToScan) {
188+
this.pathsToMatch = pathsToMatch;
189+
this.packagesToScan = packagesToScan;
190+
this.group = group;
191+
}
192+
193+
private List<String> pathsToMatch;
194+
195+
private List<String> packagesToScan;
196+
197+
private String group;
198+
199+
public List<String> getPathsToMatch() {
200+
return pathsToMatch;
201+
}
202+
203+
public void setPathsToMatch(List<String> pathsToMatch) {
204+
this.pathsToMatch = pathsToMatch;
205+
}
206+
207+
public List<String> getPackagesToScan() {
208+
return packagesToScan;
209+
}
210+
211+
public void setPackagesToScan(List<String> packagesToScan) {
212+
this.packagesToScan = packagesToScan;
213+
}
214+
215+
public String getGroup() {
216+
return group;
217+
}
218+
219+
public void setGroup(String group) {
220+
this.group = group;
221+
}
222+
}
145223
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2-
org.springdoc.core.SpringDocConfiguration
2+
org.springdoc.core.SpringDocConfiguration,\
3+
org.springdoc.core.SpringDocConfigProperties

Diff for: springdoc-openapi-kotlin/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<executions>
4646
<execution>
4747
<id>compile</id>
48+
<phase>process-sources</phase>
4849
<goals>
4950
<goal>compile</goal>
5051
</goals>

Diff for: springdoc-openapi-ui/src/main/java/org/springdoc/ui/SwaggerConfig.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public class SwaggerConfig extends WebMvcConfigurerAdapter { // NOSONAR
5757
public void addResourceHandlers(ResourceHandlerRegistry registry) {
5858
StringBuilder uiRootPath = new StringBuilder();
5959
if (swaggerPath.contains("/")) {
60-
uiRootPath.append(swaggerPath.substring(0, swaggerPath.lastIndexOf('/')));
60+
uiRootPath.append(swaggerPath, 0, swaggerPath.lastIndexOf('/'));
6161
}
6262
uiRootPath.append("/**");
6363
String webJarsLocation = webJarsPrefixUrl + DEFAULT_PATH_SEPARATOR;

Diff for: springdoc-openapi-ui/src/main/java/org/springdoc/ui/SwaggerIndexTransformer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private String readFullyAsString(InputStream inputStream)
7575
throws IOException {
7676
ByteArrayOutputStream baos = new ByteArrayOutputStream();
7777
byte[] buffer = new byte[1024];
78-
int length = 0;
78+
int length;
7979
while ((length = inputStream.read(buffer)) != -1) {
8080
baos.write(buffer, 0, length);
8181
}

Diff for: springdoc-openapi-ui/src/main/java/org/springdoc/ui/SwaggerWelcome.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ public void afterPropertiesSet() {
9090
@Operation(hidden = true)
9191
@GetMapping(SWAGGER_UI_PATH)
9292
public String redirectToUi(HttpServletRequest request) {
93-
StringBuilder sbUrl = new StringBuilder(REDIRECT_URL_PREFIX).append(this.uiRootPath);
94-
sbUrl.append(SWAGGER_UI_URL);
9593
buildConfigUrl(request);
96-
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(sbUrl.toString());
94+
String sbUrl = REDIRECT_URL_PREFIX + this.uiRootPath
95+
+ SWAGGER_UI_URL;
96+
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(sbUrl);
9797
return uriBuilder.queryParam(SwaggerUiConfigProperties.CONFIG_URL_PROPERTY, swaggerUiConfig.getConfigUrl()).build().encode().toString();
9898
}
9999

@@ -142,7 +142,7 @@ private void calculateUiRootPath() {
142142
if (StringUtils.isNotBlank(mvcServletPath))
143143
sbUrl.append(mvcServletPath);
144144
if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
145-
sbUrl.append(swaggerPath.substring(0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR)));
145+
sbUrl.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
146146
this.uiRootPath = sbUrl.toString();
147147
}
148148
}

0 commit comments

Comments
 (0)