From 562d4ebe5eee39170bac680f2783c762aeb4bd40 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 25 Oct 2022 00:22:01 +0900 Subject: [PATCH] ExceptionHandler in controller is not used by another controller. Fixes @1909 --- .../core/GenericResponseService.java | 23 +++-- .../api/v30/app197/Example2Controller.java | 23 +++++ .../api/v30/app197/ExampleController.java | 23 +++++ .../api/v30/app197/MyExceptionHandler.java | 23 +++++ .../api/v30/app197/SpringDocApp197Test.java | 34 +++++++ .../test/resources/results/3.0.1/app197.json | 88 +++++++++++++++++++ 6 files changed, 206 insertions(+), 8 deletions(-) create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/Example2Controller.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/ExampleController.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/MyExceptionHandler.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/SpringDocApp197Test.java create mode 100644 springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app197.json diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/GenericResponseService.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/GenericResponseService.java index 0a12132d1..ccd01a07b 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/GenericResponseService.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/GenericResponseService.java @@ -103,6 +103,11 @@ public class GenericResponseService { */ private final PropertyResolverUtils propertyResolverUtils; + /** + * The Controller infos. + */ + private final List controllerInfos = new ArrayList<>(); + /** * The Controller advice infos. */ @@ -234,7 +239,12 @@ public void buildGenericResponse(Components components, Map find } } synchronized (this) { - controllerAdviceInfos.add(controllerAdviceInfo); + if (AnnotatedElementUtils.hasAnnotation(objClz, ControllerAdvice.class)) { + controllerAdviceInfos.add(controllerAdviceInfo); + } + else { + controllerInfos.add(controllerAdviceInfo); + } } } } @@ -636,25 +646,22 @@ else if (returnType instanceof ParameterizedType) { * @return the generic map response */ private synchronized Map getGenericMapResponse(Class beanType) { - List controllerAdviceInfosInThisBean = controllerAdviceInfos.stream() - .filter(controllerAdviceInfo -> - new ControllerAdviceBean(controllerAdviceInfo.getControllerAdvice()).isApplicableToBeanType(beanType)) - .filter(controllerAdviceInfo -> beanType.equals(controllerAdviceInfo.getControllerAdvice().getClass())) + List controllerAdviceInfosInThisBean = controllerInfos.stream() + .filter(controllerInfo -> beanType.equals(controllerInfo.getControllerAdvice().getClass())) .collect(Collectors.toList()); Map genericApiResponseMap = controllerAdviceInfosInThisBean.stream() - .map(ControllerAdviceInfo::getApiResponseMap) + .map(ControllerAdviceInfo::getApiResponseMap) .collect(LinkedHashMap::new, Map::putAll, Map::putAll); List controllerAdviceInfosNotInThisBean = controllerAdviceInfos.stream() .filter(controllerAdviceInfo -> new ControllerAdviceBean(controllerAdviceInfo.getControllerAdvice()).isApplicableToBeanType(beanType)) - .filter(controllerAdviceInfo -> !beanType.equals(controllerAdviceInfo.getControllerAdvice().getClass())) .collect(Collectors.toList()); for (ControllerAdviceInfo controllerAdviceInfo : controllerAdviceInfosNotInThisBean) { controllerAdviceInfo.getApiResponseMap().forEach((key, apiResponse) -> { - if(!genericApiResponseMap.containsKey(key)) + if (!genericApiResponseMap.containsKey(key)) genericApiResponseMap.put(key, apiResponse); }); } diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/Example2Controller.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/Example2Controller.java new file mode 100644 index 000000000..96cef2e8f --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/Example2Controller.java @@ -0,0 +1,23 @@ +package test.org.springdoc.api.v30.app197; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/example2") +public class Example2Controller { + @GetMapping("/") + public void index() { + throw new IllegalArgumentException(); + } + + @ExceptionHandler(IllegalArgumentException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public String customControllerException() { + return "example"; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/ExampleController.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/ExampleController.java new file mode 100644 index 000000000..7e5e6d0ed --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/ExampleController.java @@ -0,0 +1,23 @@ +package test.org.springdoc.api.v30.app197; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/example") +public class ExampleController { + @GetMapping("/") + public void index() { + throw new IllegalArgumentException(); + } + + @ExceptionHandler(IllegalArgumentException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public String customControllerException() { + return "example"; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/MyExceptionHandler.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/MyExceptionHandler.java new file mode 100644 index 000000000..187756e3e --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/MyExceptionHandler.java @@ -0,0 +1,23 @@ +package test.org.springdoc.api.v30.app197; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.http.HttpStatus; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ControllerAdvice +public class MyExceptionHandler { + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler({ HttpRequestMethodNotSupportedException.class }) + @ResponseBody + public Map handleError() { + Map errorMap = new HashMap(); + errorMap.put("message", "error"); + return errorMap; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/SpringDocApp197Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/SpringDocApp197Test.java new file mode 100644 index 000000000..ec6e25a9b --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app197/SpringDocApp197Test.java @@ -0,0 +1,34 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2022 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.app197; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp197Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} + +} diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app197.json b/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app197.json new file mode 100644 index 000000000..0f5c99e89 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app197.json @@ -0,0 +1,88 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/example2/": { + "get": { + "tags": [ + "example-2-controller" + ], + "operationId": "index", + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "*/*": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + }, + "/example/": { + "get": { + "tags": [ + "example-controller" + ], + "operationId": "index_1", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "*/*": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "components": {} +}