Skip to content

Commit e02aaef

Browse files
committed
Inherited Methods Not Included in Swagger Documentation with @RouterOperation in Spring Boot WebFlux Application. Fixes #2525
1 parent ca23685 commit e02aaef

File tree

6 files changed

+149
-1
lines changed

6 files changed

+149
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ protected void calculatePath(List<RouterOperation> routerOperationList, Locale l
562562
if (StringUtils.isNotBlank(routerOperation.getBeanMethod())) {
563563
try {
564564
if (ArrayUtils.isEmpty(routerOperation.getParameterTypes())) {
565-
Method[] declaredMethods = AopUtils.getTargetClass(handlerBean).getDeclaredMethods();
565+
Method[] declaredMethods = org.springframework.util.ReflectionUtils.getAllDeclaredMethods(AopUtils.getTargetClass(handlerBean));
566566
Optional<Method> methodOptional = Arrays.stream(declaredMethods)
567567
.filter(method -> routerOperation.getBeanMethod().equals(method.getName()) && method.getParameters().length == 0)
568568
.findAny();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package test.org.springdoc.api.app191.Handler;
2+
3+
import reactor.core.publisher.Mono;
4+
5+
import org.springframework.stereotype.Component;
6+
import org.springframework.web.reactive.function.server.ServerRequest;
7+
import org.springframework.web.reactive.function.server.ServerResponse;
8+
9+
@Component
10+
public abstract class BaseHandler {
11+
protected abstract Mono<ServerResponse> apply (ServerRequest serverRequest);
12+
13+
public Mono<ServerResponse> handle(ServerRequest serverRequest) {
14+
return this.apply(serverRequest);
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package test.org.springdoc.api.app191.Handler;
2+
3+
import reactor.core.publisher.Mono;
4+
5+
import org.springframework.http.MediaType;
6+
import org.springframework.stereotype.Component;
7+
import org.springframework.web.reactive.function.server.ServerRequest;
8+
import org.springframework.web.reactive.function.server.ServerResponse;
9+
10+
@Component
11+
public class GetNameHandler extends BaseHandler{
12+
@Override
13+
protected Mono<ServerResponse> apply(ServerRequest serverRequest) {
14+
return ServerResponse.ok()
15+
.contentType(MediaType.APPLICATION_JSON)
16+
.bodyValue("Name API is called");
17+
}
18+
19+
// Since handle function is present in the BaseHandler class so it is not able to detect but it should
20+
21+
// Uncommenting below code will work as expected since now explicitly handle is declared here
22+
23+
// @Override
24+
// public Mono<ServerResponse> handle(ServerRequest serverRequest) {
25+
// return super.handle(serverRequest);
26+
// }
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package test.org.springdoc.api.app191.Router;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.media.Content;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
7+
import org.springdoc.core.annotations.RouterOperation;
8+
import org.springdoc.core.annotations.RouterOperations;
9+
import test.org.springdoc.api.app191.Handler.GetNameHandler;
10+
11+
import org.springframework.context.annotation.Bean;
12+
import org.springframework.context.annotation.Configuration;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.web.bind.annotation.RequestMethod;
15+
import org.springframework.web.reactive.function.server.RequestPredicates;
16+
import org.springframework.web.reactive.function.server.RouterFunction;
17+
import org.springframework.web.reactive.function.server.RouterFunctions;
18+
import org.springframework.web.reactive.function.server.ServerResponse;
19+
20+
21+
@Configuration
22+
public class GetNameRouter {
23+
24+
@Bean
25+
@RouterOperations(
26+
value = {
27+
@RouterOperation(path = "/v1/name", produces = {MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.GET,
28+
beanClass = GetNameHandler.class, beanMethod = "handle", operation = @Operation(operationId = "getName",
29+
description = "get name", responses = {@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class)))})
30+
)
31+
})
32+
33+
public RouterFunction<ServerResponse> routerFunction(GetNameHandler getNameHandler) {
34+
return RouterFunctions.route(RequestPredicates.GET("/v1/name"), getNameHandler::handle);
35+
}
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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.app191;
20+
21+
import test.org.springdoc.api.AbstractSpringDocTest;
22+
23+
import org.springframework.boot.autoconfigure.SpringBootApplication;
24+
import org.springframework.context.annotation.ComponentScan;
25+
26+
public class SpringDocApp191Test extends AbstractSpringDocTest {
27+
28+
@SpringBootApplication
29+
@ComponentScan(basePackages = { "org.springdoc", "test.org.springdoc.api.app191" })
30+
static class SpringDocTestApp {}
31+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/v1/name": {
15+
"get": {
16+
"tags": [
17+
"get-name-handler"
18+
],
19+
"description": "get name",
20+
"operationId": "getName",
21+
"responses": {
22+
"200": {
23+
"description": "OK",
24+
"content": {
25+
"application/json": {
26+
"schema": {
27+
"type": "string"
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
35+
},
36+
"components": {}
37+
}

0 commit comments

Comments
 (0)