Skip to content

Commit

Permalink
Inherited Methods Not Included in Swagger Documentation with @RouterO…
Browse files Browse the repository at this point in the history
…peration in Spring Boot WebFlux Application. Fixes #2525
  • Loading branch information
bnasslahsen committed Mar 30, 2024
1 parent ca23685 commit e02aaef
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 1 deletion.
Expand Up @@ -562,7 +562,7 @@ protected void calculatePath(List<RouterOperation> routerOperationList, Locale l
if (StringUtils.isNotBlank(routerOperation.getBeanMethod())) {
try {
if (ArrayUtils.isEmpty(routerOperation.getParameterTypes())) {
Method[] declaredMethods = AopUtils.getTargetClass(handlerBean).getDeclaredMethods();
Method[] declaredMethods = org.springframework.util.ReflectionUtils.getAllDeclaredMethods(AopUtils.getTargetClass(handlerBean));
Optional<Method> methodOptional = Arrays.stream(declaredMethods)
.filter(method -> routerOperation.getBeanMethod().equals(method.getName()) && method.getParameters().length == 0)
.findAny();
Expand Down
@@ -0,0 +1,16 @@
package test.org.springdoc.api.app191.Handler;

import reactor.core.publisher.Mono;

import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

@Component
public abstract class BaseHandler {
protected abstract Mono<ServerResponse> apply (ServerRequest serverRequest);

public Mono<ServerResponse> handle(ServerRequest serverRequest) {
return this.apply(serverRequest);
}
}
@@ -0,0 +1,27 @@
package test.org.springdoc.api.app191.Handler;

import reactor.core.publisher.Mono;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

@Component
public class GetNameHandler extends BaseHandler{
@Override
protected Mono<ServerResponse> apply(ServerRequest serverRequest) {
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.bodyValue("Name API is called");
}

// Since handle function is present in the BaseHandler class so it is not able to detect but it should

// Uncommenting below code will work as expected since now explicitly handle is declared here

// @Override
// public Mono<ServerResponse> handle(ServerRequest serverRequest) {
// return super.handle(serverRequest);
// }
}
@@ -0,0 +1,37 @@
package test.org.springdoc.api.app191.Router;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springdoc.core.annotations.RouterOperation;
import org.springdoc.core.annotations.RouterOperations;
import test.org.springdoc.api.app191.Handler.GetNameHandler;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;


@Configuration
public class GetNameRouter {

@Bean
@RouterOperations(
value = {
@RouterOperation(path = "/v1/name", produces = {MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.GET,
beanClass = GetNameHandler.class, beanMethod = "handle", operation = @Operation(operationId = "getName",
description = "get name", responses = {@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class)))})
)
})

public RouterFunction<ServerResponse> routerFunction(GetNameHandler getNameHandler) {
return RouterFunctions.route(RequestPredicates.GET("/v1/name"), getNameHandler::handle);
}

}
@@ -0,0 +1,31 @@
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/

package test.org.springdoc.api.app191;

import test.org.springdoc.api.AbstractSpringDocTest;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

public class SpringDocApp191Test extends AbstractSpringDocTest {

@SpringBootApplication
@ComponentScan(basePackages = { "org.springdoc", "test.org.springdoc.api.app191" })
static class SpringDocTestApp {}
}
@@ -0,0 +1,37 @@
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"servers": [
{
"url": "",
"description": "Generated server url"
}
],
"paths": {
"/v1/name": {
"get": {
"tags": [
"get-name-handler"
],
"description": "get name",
"operationId": "getName",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
},
"components": {}
}

0 comments on commit e02aaef

Please sign in to comment.