diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java index 68e66155d..793b12042 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java @@ -101,7 +101,7 @@ /** * The type Generic response builder. * - * @author bnasslahsen + * @author bnasslahsen, Max Freedom Pollard */ public class GenericResponseService implements ApplicationContextAware { @@ -450,7 +450,7 @@ private void buildGenericApiResponses(Components components, MethodParameter met else { // Use response parameters with no description filled - No documentation // available - String httpCode = evaluateResponseStatus(methodParameter.getMethod(), Objects.requireNonNull(methodParameter.getMethod()).getClass(), true); + String httpCode = evaluateResponseStatus(methodParameter.getMethod(), methodParameter.getContainingClass(), true); if (Objects.nonNull(httpCode)) { apiResponse = methodAttributes.getGenericMapResponse().containsKey(httpCode) ? methodAttributes.getGenericMapResponse().get(httpCode) : new ApiResponse(); @@ -491,16 +491,17 @@ private void buildApiResponses(Components components, MethodParameter methodPara buildApiResponses(components, methodParameter, apiResponsesOp, methodAttributes, httpCode, apiResponse, false); } } - if (AnnotatedElementUtils.hasAnnotation(methodParameter.getMethod(), ResponseStatus.class)) { + if (AnnotatedElementUtils.hasAnnotation(methodParameter.getMethod(), ResponseStatus.class) + || AnnotatedElementUtils.hasAnnotation(methodParameter.getContainingClass(), ResponseStatus.class)) { // Handles the case with @ResponseStatus, if the specified response is not already handled explicitly - String httpCode = evaluateResponseStatus(methodParameter.getMethod(), Objects.requireNonNull(methodParameter.getMethod()).getClass(), false); + String httpCode = evaluateResponseStatus(methodParameter.getMethod(), methodParameter.getContainingClass(), false); if (Objects.nonNull(httpCode) && !apiResponsesOp.containsKey(httpCode) && !apiResponsesOp.containsKey(ApiResponses.DEFAULT)) { buildApiResponses(components, methodParameter, apiResponsesOp, methodAttributes, httpCode, new ApiResponse(), false); } } } else { - String httpCode = evaluateResponseStatus(methodParameter.getMethod(), Objects.requireNonNull(methodParameter.getMethod()).getClass(), false); + String httpCode = evaluateResponseStatus(methodParameter.getMethod(), methodParameter.getContainingClass(), false); if (Objects.nonNull(httpCode)) buildApiResponses(components, methodParameter, apiResponsesOp, methodAttributes, httpCode, new ApiResponse(), false); } @@ -812,7 +813,7 @@ private boolean isValidHttpCode(String httpCode, MethodParameter methodParameter if (isHttpCodePresent(httpCode, responseSet)) result = true; } - if (httpCode.equals(evaluateResponseStatus(method, method.getClass(), false))) + if (httpCode.equals(evaluateResponseStatus(method, methodParameter.getContainingClass(), false))) result = true; } } diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app273/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app273/HelloController.java new file mode 100644 index 000000000..08155f545 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app273/HelloController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2026 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.v30.app273; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +/** + * A controller that sets a status code for all of its handler methods, and one method that + * sets its own. + * + * @author Max Freedom Pollard + */ +@RestController +@ResponseStatus(HttpStatus.CREATED) +public class HelloController { + + @PostMapping("/hello") + public String hello() { + return null; + } + + @GetMapping("/bye") + @ResponseStatus(HttpStatus.ACCEPTED) + public String bye() { + return null; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app273/SpringDocApp273Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app273/SpringDocApp273Test.java new file mode 100644 index 000000000..2f7be7d18 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app273/SpringDocApp273Test.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2026 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.v30.app273; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * A @ResponseStatus on the controller class applies to every handler method it declares. + * + * @author Max Freedom Pollard + */ +public class SpringDocApp273Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp { + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app273/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app273/HelloController.java new file mode 100644 index 000000000..19f8d0766 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app273/HelloController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2026 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.v31.app273; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +/** + * A controller that sets a status code for all of its handler methods, and one method that + * sets its own. + * + * @author Max Freedom Pollard + */ +@RestController +@ResponseStatus(HttpStatus.CREATED) +public class HelloController { + + @PostMapping("/hello") + public String hello() { + return null; + } + + @GetMapping("/bye") + @ResponseStatus(HttpStatus.ACCEPTED) + public String bye() { + return null; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app273/SpringDocApp273Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app273/SpringDocApp273Test.java new file mode 100644 index 000000000..a81dec257 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app273/SpringDocApp273Test.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2026 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.v31.app273; + +import test.org.springdoc.api.v31.AbstractSpringDocTest; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * A @ResponseStatus on the controller class applies to every handler method it declares. + * + * @author Max Freedom Pollard + */ +public class SpringDocApp273Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp { + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app273.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app273.json new file mode 100644 index 000000000..076f81df6 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app273.json @@ -0,0 +1,50 @@ +{ + "openapi" : "3.0.1", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" + }, + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/hello" : { + "post" : { + "tags" : [ "hello-controller" ], + "operationId" : "hello", + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + } + }, + "/bye" : { + "get" : { + "tags" : [ "hello-controller" ], + "operationId" : "bye", + "responses" : { + "202" : { + "description" : "Accepted", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + } + } + }, + "components" : { } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app273.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app273.json new file mode 100644 index 000000000..072f4011f --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app273.json @@ -0,0 +1,50 @@ +{ + "openapi" : "3.1.0", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" + }, + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/hello" : { + "post" : { + "tags" : [ "hello-controller" ], + "operationId" : "hello", + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + } + }, + "/bye" : { + "get" : { + "tags" : [ "hello-controller" ], + "operationId" : "bye", + "responses" : { + "202" : { + "description" : "Accepted", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + } + } + }, + "components" : { } +}