Skip to content

Commit 91e67de

Browse files
committed
Merge branch 'master' of https://github.com/springdoc/springdoc-openapi into actuator-description
� Conflicts: � springdoc-openapi-webmvc-core/src/main/java/org/springdoc/api/MultipleOpenApiResource.java � springdoc-openapi-webmvc-core/src/main/java/org/springdoc/api/OpenApiResource.java � springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app68/SpringDocApp68Test.java
2 parents ef8a9d2 + afe890a commit 91e67de

File tree

234 files changed

+1821
-1281
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

234 files changed

+1821
-1281
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [Unreleased] -
8+
### Added
9+
- Support for pathsToMatch and packagesToScan to work in spinal-case as well. Fixes #338
10+
## Fixed
11+
- Fixes springdoc.swagger-ui.url property #339
12+
13+
## [1.2.26] -
14+
### Added
15+
- Make springdoc cache configurable #331
16+
### Fixed
17+
- Multiple paths in controller and DeleteMapping generates incorrect Request Body #334
18+
719
## [1.2.25] -
820
### Fixed
921
- Fix double registration of model converters when grouped api is used #324

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[![Build Status](https://travis-ci.org/springdoc/springdoc-openapi.svg?branch=master)](https://travis-ci.org/springdoc/springdoc-openapi)
22
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=springdoc_springdoc-openapi&metric=alert_status)](https://sonarcloud.io/dashboard?id=springdoc_springdoc-openapi)
3+
[![Known Vulnerabilities](https://snyk.io/test/github/springdoc/springdoc-openapi.git/badge.svg)](https://snyk.io/test/github/springdoc/springdoc-openapi.git)
34

45
![Octocat](https://springdoc.github.io/springdoc-openapi-demos/images/springdoc-openapi.png)
56

pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>org.springdoc</groupId>
55
<artifactId>springdoc-openapi</artifactId>
6-
<version>1.2.26-SNAPSHOT</version>
6+
<version>1.2.27-SNAPSHOT</version>
77
<packaging>pom</packaging>
88
<name>Spring openapi documentation generator</name>
99
<description>Spring openapi documentation generator</description>
@@ -70,6 +70,7 @@
7070
<swagger-api.version>2.1.0</swagger-api.version>
7171
<swagger-ui.version>3.24.0</swagger-ui.version>
7272
<webjars-locator.version>0.38</webjars-locator.version>
73+
<spring-security-oauth2.version>2.3.5.RELEASE</spring-security-oauth2.version>
7374
</properties>
7475

7576
<dependencyManagement>
@@ -101,6 +102,11 @@
101102
<artifactId>webjars-locator</artifactId>
102103
<version>${webjars-locator.version}</version>
103104
</dependency>
105+
<dependency>
106+
<groupId>org.springframework.security.oauth</groupId>
107+
<artifactId>spring-security-oauth2</artifactId>
108+
<version>${spring-security-oauth2.version}</version>
109+
</dependency>
104110
</dependencies>
105111
</dependencyManagement>
106112
<dependencies>

springdoc-openapi-common/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springdoc</groupId>
77
<artifactId>springdoc-openapi</artifactId>
8-
<version>1.2.26-SNAPSHOT</version>
8+
<version>1.2.27-SNAPSHOT</version>
99
</parent>
1010
<dependencies>
1111
<dependency>

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@
2929
import java.util.stream.Collectors;
3030
import java.util.stream.Stream;
3131

32-
import static org.springdoc.core.Constants.SPRINGDOC_PACKAGES_TO_SCAN;
33-
import static org.springdoc.core.Constants.SPRINGDOC_PATHS_TO_MATCH;
32+
import static org.springdoc.core.Constants.*;
3433

3534
public abstract class AbstractOpenApiResource {
3635

@@ -46,6 +45,8 @@ public abstract class AbstractOpenApiResource {
4645
private List<String> packagesToScan;
4746
@Value(SPRINGDOC_PATHS_TO_MATCH)
4847
private List<String> pathsToMatch;
48+
@Value(SPRINGDOC_CACHE_DISABLED_VALUE)
49+
private boolean cacheDisabled;
4950

5051
protected AbstractOpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder requestBuilder,
5152
AbstractResponseBuilder responseBuilder, OperationBuilder operationParser,
@@ -60,7 +61,7 @@ protected AbstractOpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequest
6061

6162
protected AbstractOpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder requestBuilder,
6263
AbstractResponseBuilder responseBuilder, OperationBuilder operationParser,
63-
Optional<List<OpenApiCustomiser>> openApiCustomisers, List<String> pathsToMatch, List<String> packagesToScan) {
64+
Optional<List<OpenApiCustomiser>> openApiCustomisers, List<String> pathsToMatch, List<String> packagesToScan,boolean cacheDisabled) {
6465
super();
6566
this.openAPIBuilder = openAPIBuilder;
6667
this.requestBuilder = requestBuilder;
@@ -69,11 +70,12 @@ protected AbstractOpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequest
6970
this.openApiCustomisers = openApiCustomisers;
7071
this.pathsToMatch = pathsToMatch;
7172
this.packagesToScan = packagesToScan;
73+
this.cacheDisabled=cacheDisabled;
7274
}
7375

7476
protected synchronized OpenAPI getOpenApi() {
7577
OpenAPI openApi;
76-
if (!computeDone) {
78+
if (!computeDone || cacheDisabled) {
7779
Instant start = Instant.now();
7880
openAPIBuilder.build();
7981
Map<String, Object> restControllersMap = openAPIBuilder.getRestControllersMap();

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.annotation.JsonView;
44
import io.swagger.v3.oas.annotations.Hidden;
5+
import io.swagger.v3.oas.annotations.enums.ParameterIn;
56
import io.swagger.v3.oas.models.Components;
67
import io.swagger.v3.oas.models.Operation;
78
import io.swagger.v3.oas.models.media.Schema;
@@ -174,7 +175,7 @@ protected Parameter customiseParameter(Parameter parameter, ParameterInfo parame
174175
}
175176

176177
protected boolean isParamToIgnore(java.lang.reflect.Parameter parameter) {
177-
if (parameter.isAnnotationPresent(PathVariable.class)) {
178+
if (parameter.isAnnotationPresent(PathVariable.class) || parameter.isAnnotationPresent(RequestParam.class)) {
178179
return false;
179180
}
180181
return parameterBuilder.isAnnotationToIgnore(parameter) || PARAM_TYPES_TO_IGNORE.contains(parameter.getType()) || (AnnotationUtils.findAnnotation(parameter.getType(), Hidden.class) != null);
@@ -224,9 +225,8 @@ private Parameter buildParams(ParameterInfo parameterInfo, Components components
224225
requestInfo = new RequestInfo(ParameterType.PATH_PARAM, pathVar.value(), Boolean.TRUE, null);
225226
parameter = buildParam(parameterInfo, components, requestInfo, jsonView);
226227
}
227-
228228
// By default
229-
if (RequestMethod.GET.equals(requestMethod)) {
229+
if (RequestMethod.GET.equals(requestMethod) || (parameterInfo.getParameterModel() != null && ParameterIn.PATH.toString().equals(parameterInfo.getParameterModel().getIn()))) {
230230
parameter = this.buildParam(QUERY_PARAM, components, parameterInfo, Boolean.TRUE, null, jsonView);
231231
}
232232

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,19 @@ public final class Constants {
1111
public static final String SWAGGER_CONFIG_URL = API_DOCS_URL + DEFAULT_PATH_SEPARATOR + SWAGGGER_CONFIG_FILE;
1212
public static final String DEFAULT_API_DOCS_URL_YAML = API_DOCS_URL + ".yaml";
1313
public static final String SPRINGDOC_ENABLED = "springdoc.api-docs.enabled";
14+
public static final String SPRINGDOC_CACHE_DISABLED = "springdoc.cache.disabled";
15+
public static final String SPRINGDOC_CACHE_DISABLED_VALUE= "${" + SPRINGDOC_CACHE_DISABLED + ":false}";
1416
public static final String SPRINGDOC_SWAGGER_UI_ENABLED = "springdoc.swagger-ui.enabled";
17+
public static final String SPRINGDOC_SWAGGER_UI_CONFIG_URL ="springdoc.swagger-ui.configUrl";
18+
public static final String SPRINGDOC_SWAGGER_UI_URL ="springdoc.swagger-ui.url";
19+
public static final String SPRINGDOC_SWAGGER_UI_URL_VALUE ="${" + SPRINGDOC_SWAGGER_UI_URL + ":#{null}}";
20+
public static final String SPRINGDOC_OAUTH2_REDIRECT_URL ="springdoc.swagger-ui.oauth2RedirectUrl";
21+
public static final String SPRINGDOC_OAUTH2_REDIRECT_URL_VALUE ="${" + SPRINGDOC_OAUTH2_REDIRECT_URL + ":#{null}}";
22+
public static final String SPRINGDOC_SWAGGER_UI_CONFIG_URL_VALUE ="${" + SPRINGDOC_SWAGGER_UI_CONFIG_URL + ":#{null}}";
1523
public static final String SPRINGDOC_SHOW_ACTUATOR = "springdoc.show-actuator";
1624
public static final String SPRINGDOC_SHOW_ACTUATOR_VALUE = "${" + SPRINGDOC_SHOW_ACTUATOR + ":false}";
17-
public static final String SPRINGDOC_PACKAGES_TO_SCAN = "${springdoc.packagesToScan:#{null}}";
18-
public static final String SPRINGDOC_PATHS_TO_MATCH = "${springdoc.pathsToMatch:#{null}}";
25+
public static final String SPRINGDOC_PACKAGES_TO_SCAN = "${springdoc.packages-to-scan:#{null}}";
26+
public static final String SPRINGDOC_PATHS_TO_MATCH = "${springdoc.paths-to-match:#{null}}";
1927
public static final String SPRINGDOC_ACTUATOR_TAG = "Actuator";
2028
public static final String SPRINGDOC_ACTUATOR_DESCRIPTION = "Monitor and interact";
2129
public static final String SPRINGDOC_ACTUATOR_DOC_URL = "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/";
@@ -37,7 +45,6 @@ public final class Constants {
3745
public static final String HEAD_METHOD = "head";
3846
public static final String OPTIONS_METHOD = "options";
3947
public static final String QUERY_PARAM = "query";
40-
4148
public static final String DEFAULT_DESCRIPTION = "default response";
4249
public static final String DEFAULT_TITLE = "OpenAPI definition";
4350
public static final String DEFAULT_VERSION = "v0";

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,31 @@ public class OpenAPIBuilder {
4646

4747
private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIBuilder.class);
4848
private final OpenAPI openAPI;
49+
private boolean isServersPresent = false;
4950
private final ApplicationContext context;
5051
private final SecurityParser securityParser;
5152
private final Map<HandlerMethod, io.swagger.v3.oas.models.tags.Tag> springdocTags = new HashMap<>();
5253
private String serverBaseUrl;
54+
private final Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider;
5355

5456
@SuppressWarnings("WeakerAccess")
55-
OpenAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser) {
57+
OpenAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser, Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider) {
5658
if (openAPI.isPresent()) {
5759
this.openAPI = openAPI.get();
5860
if (this.openAPI.getComponents() == null)
5961
this.openAPI.setComponents(new Components());
6062
if (this.openAPI.getPaths() == null)
6163
this.openAPI.setPaths(new Paths());
64+
if (!CollectionUtils.isEmpty(this.openAPI.getServers()))
65+
this.isServersPresent = true;
6266
} else {
6367
this.openAPI = new OpenAPI();
6468
this.openAPI.setComponents(new Components());
6569
this.openAPI.setPaths(new Paths());
6670
}
6771
this.context = context;
6872
this.securityParser = securityParser;
73+
this.springSecurityOAuth2Provider = springSecurityOAuth2Provider;
6974
}
7075

7176
private static String splitCamelCase(String str) {
@@ -102,9 +107,11 @@ else if (openAPI.getInfo() == null) {
102107
openAPI.setInfo(infos);
103108
}
104109
// default server value
105-
if (CollectionUtils.isEmpty(openAPI.getServers())) {
110+
if (CollectionUtils.isEmpty(openAPI.getServers()) || !isServersPresent) {
106111
Server server = new Server().url(serverBaseUrl).description(DEFAULT_SERVER_DESCRIPTION);
107-
openAPI.addServersItem(server);
112+
List servers = new ArrayList();
113+
servers.add(server);
114+
openAPI.setServers(servers);
108115
}
109116
// add security schemes
110117
this.calculateSecuritySchemes(openAPI.getComponents());
@@ -201,15 +208,27 @@ private Optional<OpenAPIDefinition> getOpenAPIDefinition() {
201208

202209
private void buildOpenAPIWithOpenAPIDefinition(OpenAPI openAPI, OpenAPIDefinition apiDef) {
203210
// info
204-
AnnotationsUtils.getInfo(apiDef.info()).ifPresent(openAPI::setInfo);
211+
Optional<Info> infos = AnnotationsUtils.getInfo(apiDef.info());
212+
if (infos.isPresent()) {
213+
Info info = infos.get();
214+
if (StringUtils.isNotBlank(info.getTitle())) {
215+
PropertyResolverUtils propertyResolverUtils = context.getBean(PropertyResolverUtils.class);
216+
info.title(propertyResolverUtils.resolve(info.getTitle()));
217+
}
218+
openAPI.setInfo(info);
219+
}
205220
// OpenApiDefinition security requirements
206221
securityParser.getSecurityRequirements(apiDef.security()).ifPresent(openAPI::setSecurity);
207222
// OpenApiDefinition external docs
208223
AnnotationsUtils.getExternalDocumentation(apiDef.externalDocs()).ifPresent(openAPI::setExternalDocs);
209224
// OpenApiDefinition tags
210225
AnnotationsUtils.getTags(apiDef.tags(), false).ifPresent(tags -> openAPI.setTags(new ArrayList<>(tags)));
211226
// OpenApiDefinition servers
212-
openAPI.setServers(AnnotationsUtils.getServers(apiDef.servers()).orElse(null));
227+
Optional<List<Server>> optionalServers = AnnotationsUtils.getServers(apiDef.servers());
228+
if (optionalServers.isPresent()) {
229+
openAPI.setServers(optionalServers.get());
230+
this.isServersPresent = true;
231+
}
213232
// OpenApiDefinition extensions
214233
if (apiDef.extensions().length > 0) {
215234
openAPI.setExtensions(AnnotationsUtils.getExtensions(apiDef.extensions()));
@@ -313,4 +332,8 @@ public Map<String, Object> getControllerAdviceMap() {
313332
controller -> (AnnotationUtils.findAnnotation(controller.getValue().getClass(), Hidden.class) == null))
314333
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a1, a2) -> a1));
315334
}
335+
336+
public Optional<SecurityOAuth2Provider> getSpringSecurityOAuth2Provider() {
337+
return springSecurityOAuth2Provider;
338+
}
316339
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.springdoc.core;
2+
3+
import java.util.Map;
4+
5+
public interface SecurityOAuth2Provider {
6+
7+
Map getHandlerMethods();
8+
9+
Map<String, Object> getFrameworkEndpoints();
10+
}

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import org.springdoc.core.converters.ObjectNodeConverter;
77
import org.springdoc.core.converters.PropertyCustomizingConverter;
88
import org.springdoc.core.customizers.PropertyCustomizer;
9+
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
910
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
10-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
11-
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
11+
import org.springframework.boot.autoconfigure.condition.*;
1212
import org.springframework.context.ApplicationContext;
1313
import org.springframework.context.annotation.Bean;
1414
import org.springframework.context.annotation.Configuration;
@@ -18,6 +18,7 @@
1818
import java.util.List;
1919
import java.util.Optional;
2020

21+
import static org.springdoc.core.Constants.SPRINGDOC_CACHE_DISABLED;
2122
import static org.springdoc.core.Constants.SPRINGDOC_ENABLED;
2223

2324
@Configuration
@@ -45,8 +46,8 @@ IgnoredParameterAnnotationsDefault ignoredParameterAnnotationsDefault() {
4546
}
4647

4748
@Bean
48-
public OpenAPIBuilder openAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser) {
49-
return new OpenAPIBuilder(openAPI, context, securityParser);
49+
public OpenAPIBuilder openAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context, SecurityParser securityParser,Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider) {
50+
return new OpenAPIBuilder(openAPI, context, securityParser,springSecurityOAuth2Provider);
5051
}
5152

5253
@Bean
@@ -78,4 +79,34 @@ public SecurityParser securityParser(PropertyResolverUtils propertyResolverUtils
7879
return new SecurityParser(propertyResolverUtils);
7980
}
8081

82+
static class ConditionOnCacheOrGroupedOpenApi extends AnyNestedCondition {
83+
84+
ConditionOnCacheOrGroupedOpenApi() {
85+
super(ConfigurationPhase.REGISTER_BEAN);
86+
}
87+
88+
@Bean
89+
@ConditionalOnBean(GroupedOpenApi.class)
90+
public BeanFactoryPostProcessor beanFactoryPostProcessor1() {
91+
return getBeanFactoryPostProcessor();
92+
}
93+
94+
@Bean
95+
@ConditionalOnProperty(name = SPRINGDOC_CACHE_DISABLED)
96+
@ConditionalOnMissingBean(GroupedOpenApi.class)
97+
public BeanFactoryPostProcessor beanFactoryPostProcessor2() {
98+
return getBeanFactoryPostProcessor();
99+
}
100+
101+
private BeanFactoryPostProcessor getBeanFactoryPostProcessor() {
102+
return beanFactory -> {
103+
for (String beanName : beanFactory.getBeanNamesForType(OpenAPIBuilder.class)) {
104+
beanFactory.getBeanDefinition(beanName).setScope("prototype");
105+
}
106+
for (String beanName : beanFactory.getBeanNamesForType(OpenAPI.class)) {
107+
beanFactory.getBeanDefinition(beanName).setScope("prototype");
108+
}
109+
};
110+
}
111+
}
81112
}

0 commit comments

Comments
 (0)