Skip to content

Commit 85211de

Browse files
author
bnasslahsen
committed
Improve Reverse proxy compatibily for webflux. Fixes #435
1 parent 88327e6 commit 85211de

File tree

11 files changed

+200
-166
lines changed

11 files changed

+200
-166
lines changed

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,11 @@ protected synchronized OpenAPI getOpenApi() {
139139
LOGGER.info("Init duration for springdoc-openapi is: {} ms",
140140
Duration.between(start, Instant.now()).toMillis());
141141
}
142-
else
142+
else {
143+
if(!openAPIBuilder.isServersPresent())
144+
openAPIBuilder.updateServers(openAPIBuilder.getCachedOpenAPI());
143145
openApi = openAPIBuilder.getCachedOpenAPI();
146+
}
144147
return openApi;
145148
}
146149

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

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

8383
public static final String SWAGGER_UI_PATH = "${springdoc.swagger-ui.path:#{T(org.springdoc.core.Constants).DEFAULT_SWAGGER_UI_PATH}}";
8484

85-
public static final String MVC_SERVLET_PATH = "${spring.mvc.servlet.path" + NULL + "}";
86-
8785
public static final String DEFAULT_GROUP_NAME="springdocDefault";
8886

8987
public static final String GET_METHOD = "get";

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

+24-14
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public class OpenAPIBuilder {
8585

8686
private final Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider;
8787

88-
private boolean isServersPresent = false;
88+
private boolean isServersPresent;
8989

9090
private String serverBaseUrl;
9191

@@ -105,7 +105,7 @@ public class OpenAPIBuilder {
105105
this.context = context;
106106
this.securityParser = securityParser;
107107
this.springSecurityOAuth2Provider = springSecurityOAuth2Provider;
108-
this.springDocConfigProperties=springDocConfigProperties;
108+
this.springDocConfigProperties = springDocConfigProperties;
109109
}
110110

111111
private static String splitCamelCase(String str) {
@@ -130,13 +130,13 @@ public Paths getPaths() {
130130
public void build() {
131131
Optional<OpenAPIDefinition> apiDef = getOpenAPIDefinition();
132132

133-
if(openAPI==null){
133+
if (openAPI == null) {
134134
this.calculatedOpenAPI = new OpenAPI();
135135
this.calculatedOpenAPI.setComponents(new Components());
136136
this.calculatedOpenAPI.setPaths(new Paths());
137137
}
138138
else
139-
this.calculatedOpenAPI=openAPI;
139+
this.calculatedOpenAPI = openAPI;
140140

141141
if (apiDef.isPresent()) {
142142
buildOpenAPIWithOpenAPIDefinition(calculatedOpenAPI, apiDef.get());
@@ -148,15 +148,23 @@ else if (calculatedOpenAPI.getInfo() == null) {
148148
}
149149
// default server value
150150
if (CollectionUtils.isEmpty(calculatedOpenAPI.getServers()) || !isServersPresent) {
151-
Server server = new Server().url(serverBaseUrl).description(DEFAULT_SERVER_DESCRIPTION);
152-
List<Server> servers = new ArrayList();
153-
servers.add(server);
154-
calculatedOpenAPI.setServers(servers);
151+
this.updateServers(calculatedOpenAPI);
155152
}
156153
// add security schemes
157154
this.calculateSecuritySchemes(calculatedOpenAPI.getComponents());
158155
}
159156

157+
public void updateServers(OpenAPI openAPI) {
158+
Server server = new Server().url(serverBaseUrl).description(DEFAULT_SERVER_DESCRIPTION);
159+
List<Server> servers = new ArrayList();
160+
servers.add(server);
161+
openAPI.setServers(servers);
162+
}
163+
164+
public boolean isServersPresent() {
165+
return isServersPresent;
166+
}
167+
160168
public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI) {
161169
// class tags
162170
List<Tag> classTags =
@@ -208,18 +216,20 @@ public Operation buildTags(HandlerMethod handlerMethod, Operation operation, Ope
208216
else
209217
securityParser.buildSecurityRequirement(securityRequirements, operation);
210218
}
211-
212-
if (!CollectionUtils.isEmpty(tagsStr)) {
219+
if (!CollectionUtils.isEmpty(tagsStr))
213220
operation.setTags(new ArrayList<>(tagsStr));
214-
}
215221

216-
if (CollectionUtils.isEmpty(operation.getTags()) && springDocConfigProperties.isAutoTagClasses()) {
222+
223+
if (isAutoTagClasses(operation))
217224
operation.addTagsItem(splitCamelCase(handlerMethod.getBeanType().getSimpleName()));
218-
}
219225

220226
return operation;
221227
}
222228

229+
private boolean isAutoTagClasses(Operation operation) {
230+
return CollectionUtils.isEmpty(operation.getTags()) && springDocConfigProperties.isAutoTagClasses();
231+
}
232+
223233
public void setServerBaseUrl(String serverBaseUrl) {
224234
this.serverBaseUrl = serverBaseUrl;
225235
}
@@ -424,6 +434,6 @@ public OpenAPI getCalculatedOpenAPI() {
424434
}
425435

426436
public void resetCalculatedOpenAPI() {
427-
this.calculatedOpenAPI=null;
437+
this.calculatedOpenAPI = null;
428438
}
429439
}

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.net.URL;
2222
import java.util.Comparator;
2323
import java.util.HashSet;
24+
import java.util.LinkedHashSet;
2425
import java.util.List;
2526
import java.util.Map;
2627
import java.util.Objects;
@@ -379,11 +380,11 @@ public boolean isValidUrl(String url) {
379380
private void put(String urls, Set<SwaggerUrl> swaggerUrls, Map<String, Object> params) {
380381
Comparator<SwaggerUrl> swaggerUrlComparator;
381382
if (groupsOrder.isAscending())
382-
swaggerUrlComparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
383+
swaggerUrlComparator = Comparator.comparing(SwaggerUrl::getName);
383384
else
384385
swaggerUrlComparator = (h1, h2) -> h2.getName().compareTo(h1.getName());
385386

386-
swaggerUrls = swaggerUrls.stream().sorted(swaggerUrlComparator).filter(elt -> StringUtils.isNotEmpty(elt.getUrl())).collect(Collectors.toSet());
387+
swaggerUrls = swaggerUrls.stream().sorted(swaggerUrlComparator).filter(elt -> StringUtils.isNotEmpty(elt.getUrl())).collect(Collectors.toCollection(LinkedHashSet::new));
387388
if (!CollectionUtils.isEmpty(swaggerUrls)) {
388389
params.put(urls, swaggerUrls);
389390
}

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@
3232

3333
public class AdditionalModelsConverter implements ModelConverter {
3434

35-
private static Map<Class, Class> modelToClassMap= new HashMap();
36-
private static Map<Class, Schema> modelToSchemaMap= new HashMap();
35+
private static final Map<Class, Class> modelToClassMap= new HashMap();
36+
private static final Map<Class, Schema> modelToSchemaMap= new HashMap();
37+
3738
@Override
3839
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
3940
JavaType javaType = Json.mapper().constructType(type.getType());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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 org.springdoc.ui;
20+
21+
import org.apache.commons.lang3.ArrayUtils;
22+
import org.apache.commons.lang3.StringUtils;
23+
import org.springdoc.core.SpringDocConfigProperties;
24+
import org.springdoc.core.SwaggerUiConfigProperties;
25+
26+
import org.springframework.beans.factory.InitializingBean;
27+
import org.springframework.beans.factory.annotation.Value;
28+
import org.springframework.web.util.UriComponentsBuilder;
29+
30+
import static org.springdoc.core.Constants.SPRINGDOC_OAUTH2_REDIRECT_URL_VALUE;
31+
import static org.springdoc.core.Constants.SPRINGDOC_SWAGGER_UI_CONFIG_URL_VALUE;
32+
import static org.springdoc.core.Constants.SPRINGDOC_SWAGGER_UI_URL_VALUE;
33+
import static org.springdoc.core.Constants.SWAGGER_UI_OAUTH_REDIRECT_URL;
34+
import static org.springdoc.core.Constants.SWAGGGER_CONFIG_FILE;
35+
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
36+
37+
38+
public abstract class AbstractSwaggerWelcome implements InitializingBean {
39+
40+
protected final SwaggerUiConfigProperties swaggerUiConfig;
41+
42+
protected final SpringDocConfigProperties springDocConfigProperties;
43+
44+
protected String uiRootPath;
45+
46+
@Value(SPRINGDOC_SWAGGER_UI_CONFIG_URL_VALUE)
47+
private String originConfigUrl;
48+
49+
@Value(SPRINGDOC_OAUTH2_REDIRECT_URL_VALUE)
50+
private String oauth2RedirectUrl;
51+
52+
@Value(SPRINGDOC_SWAGGER_UI_URL_VALUE)
53+
private String swaggerUiUrl;
54+
55+
public AbstractSwaggerWelcome(SwaggerUiConfigProperties swaggerUiConfig, SpringDocConfigProperties springDocConfigProperties) {
56+
this.swaggerUiConfig = swaggerUiConfig;
57+
this.springDocConfigProperties = springDocConfigProperties;
58+
}
59+
60+
@Override
61+
public void afterPropertiesSet() {
62+
calculateUiRootPath();
63+
}
64+
65+
66+
protected void calculateUiRootPath(StringBuilder... sbUrls) {
67+
StringBuilder sbUrl = new StringBuilder();
68+
if (ArrayUtils.isNotEmpty(sbUrls))
69+
sbUrl = sbUrls[0];
70+
String swaggerPath = swaggerUiConfig.getPath();
71+
if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
72+
sbUrl.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
73+
this.uiRootPath = sbUrl.toString();
74+
}
75+
76+
protected String buildUrl(String contextPath, final String docsUrl) {
77+
if (contextPath.endsWith(DEFAULT_PATH_SEPARATOR)) {
78+
return contextPath.substring(0, contextPath.length() - 1) + docsUrl;
79+
}
80+
return contextPath + docsUrl;
81+
}
82+
83+
void buildConfigUrl(String contextPath, UriComponentsBuilder uriComponentsBuilder) {
84+
String apiDocsUrl = springDocConfigProperties.getApiDocs().getPath();
85+
if (StringUtils.isEmpty(originConfigUrl)) {
86+
String url = buildUrl(contextPath, apiDocsUrl);
87+
String swaggerConfigUrl = url + DEFAULT_PATH_SEPARATOR + SWAGGGER_CONFIG_FILE;
88+
swaggerUiConfig.setConfigUrl(swaggerConfigUrl);
89+
if (SwaggerUiConfigProperties.getSwaggerUrls().isEmpty()) {
90+
if (StringUtils.isEmpty(swaggerUiUrl))
91+
swaggerUiConfig.setUrl(url);
92+
else
93+
swaggerUiConfig.setUrl(swaggerUiUrl);
94+
}
95+
else
96+
SwaggerUiConfigProperties.addUrl(url);
97+
}
98+
if (StringUtils.isEmpty(oauth2RedirectUrl)) {
99+
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(SWAGGER_UI_OAUTH_REDIRECT_URL).build().toString());
100+
}
101+
else if (!swaggerUiConfig.isValidUrl(swaggerUiConfig.getOauth2RedirectUrl())) {
102+
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(swaggerUiConfig.getOauth2RedirectUrl()).build().toString());
103+
}
104+
}
105+
106+
}

Diff for: springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app1/HelloController.java

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ public class HelloController {
3232

3333
@GetMapping(value = "/search", produces = { "application/xml", "application/json" })
3434
public ResponseEntity<List<PersonDTO>> getAllPets(@NotNull Pageable pageable) {
35-
System.out.println(pageable);
3635
return null;
3736
}
3837

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
package org.springdoc.ui;
2020

2121
import com.fasterxml.jackson.databind.ObjectMapper;
22+
import org.springdoc.core.SpringDocConfigProperties;
2223
import org.springdoc.core.SpringDocConfiguration;
24+
import org.springdoc.core.SwaggerUiConfigProperties;
2325
import org.springdoc.core.SwaggerUiOAuthProperties;
2426

2527
import org.springframework.beans.factory.annotation.Autowired;
2628
import org.springframework.beans.factory.annotation.Value;
2729
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2830
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
31+
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
2932
import org.springframework.context.annotation.Bean;
3033
import org.springframework.context.annotation.Configuration;
3134
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@@ -68,8 +71,8 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
6871

6972
@Bean
7073
@ConditionalOnProperty(name = SPRINGDOC_SWAGGER_UI_ENABLED, matchIfMissing = true)
71-
public SwaggerWelcome swaggerWelcome() {
72-
return new SwaggerWelcome();
74+
public SwaggerWelcome swaggerWelcome(SwaggerUiConfigProperties swaggerUiConfig, SpringDocConfigProperties springDocConfigProperties, WebMvcProperties webMvcProperties) {
75+
return new SwaggerWelcome( swaggerUiConfig, springDocConfigProperties, webMvcProperties);
7376
}
7477

7578
@Bean

0 commit comments

Comments
 (0)