Skip to content

Commit 14cb595

Browse files
author
bnasslahsen
committed
Support REST Controllers with default empty @RequestMapping #378
1 parent 8a36e6c commit 14cb595

File tree

21 files changed

+436
-31
lines changed

21 files changed

+436
-31
lines changed

Diff for: pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
<swagger-api.version>2.1.1</swagger-api.version>
7272
<swagger-ui.version>3.24.3</swagger-ui.version>
7373
<webjars-locator.version>0.38</webjars-locator.version>
74-
<spring-security-oauth2.version>2.3.5.RELEASE</spring-security-oauth2.version>
74+
<spring-security-oauth2.version>2.3.8.RELEASE</spring-security-oauth2.version>
7575
</properties>
7676

7777
<dependencyManagement>

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

+19-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import java.nio.charset.StandardCharsets;
2525
import java.time.Duration;
2626
import java.time.Instant;
27+
import java.util.ArrayList;
2728
import java.util.Arrays;
29+
import java.util.HashSet;
2830
import java.util.List;
2931
import java.util.Map;
3032
import java.util.Objects;
@@ -80,6 +82,8 @@ public abstract class AbstractOpenApiResource {
8082

8183
private final SpringDocConfigProperties springDocConfigProperties;
8284

85+
private static final List<Class<?>> ADDITIONAL_REST_CONTROLLERS = new ArrayList<>();
86+
8387
private boolean computeDone;
8488

8589
private final String groupName;
@@ -104,7 +108,8 @@ protected synchronized OpenAPI getOpenApi() {
104108
openAPIBuilder.build();
105109
Map<String, Object> restControllersMap = openAPIBuilder.getRestControllersMap();
106110
Map<String, Object> requestMappingMap = openAPIBuilder.getRequestMappingMap();
107-
Map<String, Object> restControllers = Stream.of(restControllersMap, requestMappingMap)
111+
Map<String, Object> controllerMap = openAPIBuilder.getControllersMap();
112+
Map<String, Object> restControllers = Stream.of(restControllersMap, requestMappingMap, controllerMap)
108113
.flatMap(mapEl -> mapEl.entrySet().stream())
109114
.filter(controller -> (AnnotationUtils.findAnnotation(controller.getValue().getClass(),
110115
Hidden.class) == null))
@@ -344,4 +349,17 @@ protected String decode(String requestURI) {
344349
return requestURI;
345350
}
346351
}
352+
353+
protected boolean isAdditionalRestController(Class<?> rawClass) {
354+
return ADDITIONAL_REST_CONTROLLERS.stream().anyMatch(clazz -> clazz.isAssignableFrom(rawClass));
355+
}
356+
357+
public static void addRestControllers(Class<?>... classes){
358+
ADDITIONAL_REST_CONTROLLERS.addAll(Arrays.asList(classes));
359+
}
360+
361+
protected Set getDefaultAllowedHttpMethods(){
362+
RequestMethod[] allowedRequestMethods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.PATCH, RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.HEAD} ;
363+
return new HashSet<>(Arrays.asList(allowedRequestMethods));
364+
}
347365
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
5757
import org.springframework.core.annotation.AnnotationUtils;
5858
import org.springframework.core.type.filter.AnnotationTypeFilter;
59+
import org.springframework.stereotype.Controller;
5960
import org.springframework.util.CollectionUtils;
6061
import org.springframework.web.bind.annotation.ControllerAdvice;
6162
import org.springframework.web.bind.annotation.RequestMapping;
@@ -388,6 +389,10 @@ public Map<String, Object> getRequestMappingMap() {
388389
return context.getBeansWithAnnotation(RequestMapping.class);
389390
}
390391

392+
public Map<String, Object> getControllersMap() {
393+
return context.getBeansWithAnnotation(Controller.class);
394+
}
395+
391396
public Map<String, Object> getControllerAdviceMap() {
392397
Map<String, Object> controllerAdviceMap = context.getBeansWithAnnotation(ControllerAdvice.class);
393398
return Stream.of(controllerAdviceMap).flatMap(mapEl -> mapEl.entrySet().stream()).filter(

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import java.util.stream.Collectors;
3131

3232
import io.swagger.v3.core.util.AnnotationsUtils;
33-
import io.swagger.v3.core.util.ReflectionUtils;
3433
import io.swagger.v3.oas.annotations.Hidden;
3534
import io.swagger.v3.oas.models.Components;
3635
import io.swagger.v3.oas.models.OpenAPI;
@@ -45,6 +44,7 @@
4544
import io.swagger.v3.oas.models.responses.ApiResponses;
4645
import org.apache.commons.lang3.StringUtils;
4746

47+
import org.springframework.core.annotation.AnnotationUtils;
4848
import org.springframework.util.CollectionUtils;
4949

5050
import static org.springdoc.core.Constants.DEFAULT_DESCRIPTION;
@@ -128,10 +128,10 @@ public OpenAPI parse(Components components, io.swagger.v3.oas.annotations.Operat
128128
}
129129

130130
public boolean isHidden(Method method) {
131-
io.swagger.v3.oas.annotations.Operation apiOperation = ReflectionUtils.getAnnotation(method,
131+
io.swagger.v3.oas.annotations.Operation apiOperation = AnnotationUtils.findAnnotation(method,
132132
io.swagger.v3.oas.annotations.Operation.class);
133133
return (apiOperation != null && (apiOperation.hidden()))
134-
|| (ReflectionUtils.getAnnotation(method, Hidden.class) != null);
134+
|| (AnnotationUtils.findAnnotation(method, Hidden.class) != null);
135135
}
136136

137137
public Optional<Map<String, Callback>> buildCallbacks(

Diff for: springdoc-openapi-security/src/test/resources/results/app4.json

+42-9
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,39 @@
107107
}
108108
}
109109
}
110+
},
111+
"/oauth/check_token": {
112+
"post": {
113+
"tags": [
114+
"check-token-endpoint"
115+
],
116+
"operationId": "checkToken",
117+
"parameters": [
118+
{
119+
"name": "token",
120+
"in": "query",
121+
"required": true,
122+
"schema": {
123+
"type": "string"
124+
}
125+
}
126+
],
127+
"responses": {
128+
"200": {
129+
"description": "default response",
130+
"content": {
131+
"*/*": {
132+
"schema": {
133+
"type": "object",
134+
"additionalProperties": {
135+
"type": "object"
136+
}
137+
}
138+
}
139+
}
140+
}
141+
}
142+
}
110143
}
111144
},
112145
"components": {
@@ -129,11 +162,9 @@
129162
"type": "string",
130163
"format": "date-time"
131164
},
132-
"tokenType": {
133-
"type": "string"
134-
},
135-
"expired": {
136-
"type": "boolean"
165+
"expiresIn": {
166+
"type": "integer",
167+
"format": "int32"
137168
},
138169
"scope": {
139170
"uniqueItems": true,
@@ -148,12 +179,14 @@
148179
"type": "object"
149180
}
150181
},
182+
"expired": {
183+
"type": "boolean"
184+
},
185+
"tokenType": {
186+
"type": "string"
187+
},
151188
"refreshToken": {
152189
"$ref": "#/components/schemas/OAuth2RefreshToken"
153-
},
154-
"expiresIn": {
155-
"type": "integer",
156-
"format": "int32"
157190
}
158191
}
159192
},

Diff for: springdoc-openapi-webflux-core/src/main/java/org/springdoc/api/OpenApiResource.java

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ protected void getPaths(Map<String, Object> restControllers) {
102102
if (operationPath.startsWith(DEFAULT_PATH_SEPARATOR)
103103
&& restControllers.containsKey(handlerMethod.getBean().toString()) && isPackageToScan(handlerMethod.getBeanType().getPackage().getName()) && isPathToMatch(operationPath)) {
104104
Set<RequestMethod> requestMethods = requestMappingInfo.getMethodsCondition().getMethods();
105+
// default allowed requestmethods
106+
if (requestMethods.isEmpty())
107+
requestMethods = this.getDefaultAllowedHttpMethods();
105108
calculatePath(openAPIBuilder, handlerMethod, operationPath, requestMethods);
106109
}
107110
}

Diff for: springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public abstract class AbstractSpringDocTest {
4545
protected String groupName = "";
4646

4747
@Autowired
48-
private WebTestClient webTestClient;
48+
protected WebTestClient webTestClient;
4949

5050
public static String getContent(String fileName) throws Exception {
5151
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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.app67;
20+
21+
import org.springframework.web.bind.annotation.RequestMapping;
22+
import org.springframework.web.bind.annotation.RestController;
23+
24+
@RestController
25+
@RequestMapping("/api")
26+
public class HelloController {
27+
28+
@RequestMapping
29+
public String test() {
30+
return "ok";
31+
}
32+
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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.app67;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.springdoc.core.Constants;
23+
import test.org.springdoc.api.AbstractSpringDocTest;
24+
25+
import org.springframework.boot.autoconfigure.SpringBootApplication;
26+
import org.springframework.context.annotation.ComponentScan;
27+
28+
public class SpringDocApp67Test extends AbstractSpringDocTest {
29+
30+
@SpringBootApplication
31+
@ComponentScan(basePackages = { "org.springdoc", "test.org.springdoc.api.app67" })
32+
static class SpringDocTestApp {}
33+
34+
@Test
35+
public void testApp() throws Exception {
36+
webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + groupName).exchange().expectStatus().isOk().expectBody()
37+
.jsonPath("$.openapi").isEqualTo("3.0.1")
38+
.jsonPath("$.paths./api.get.tags[0]").isEqualTo("hello-controller")
39+
.jsonPath("$.paths./api.get.responses.200.content.['*/*'].schema.type").isEqualTo("string")
40+
.jsonPath("$.paths./api.post.tags[0]").isEqualTo("hello-controller")
41+
.jsonPath("$.paths./api.post.responses.200.content.['*/*'].schema.type").isEqualTo("string")
42+
.jsonPath("$.paths./api.put.tags[0]").isEqualTo("hello-controller")
43+
.jsonPath("$.paths./api.put.responses.200.content.['*/*'].schema.type").isEqualTo("string")
44+
.jsonPath("$.paths./api.patch.tags[0]").isEqualTo("hello-controller")
45+
.jsonPath("$.paths./api.patch.responses.200.content.['*/*'].schema.type").isEqualTo("string")
46+
.jsonPath("$.paths./api.delete.tags[0]").isEqualTo("hello-controller")
47+
.jsonPath("$.paths./api.delete.responses.200.content.['*/*'].schema.type").isEqualTo("string")
48+
.jsonPath("$.paths./api.options.tags[0]").isEqualTo("hello-controller")
49+
.jsonPath("$.paths./api.options.responses.200.content.['*/*'].schema.type").isEqualTo("string")
50+
.jsonPath("$.paths./api.head.tags[0]").isEqualTo("hello-controller")
51+
.jsonPath("$.paths./api.head.responses.200.content.['*/*'].schema.type").isEqualTo("string");
52+
}
53+
}

0 commit comments

Comments
 (0)