diff --git a/pom.xml b/pom.xml index f2ab9d3049519f6a30c5911e54b1053bc205bdad..5b674b88f1f5904d2f838f128d22d424f0581f31 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ </parent> <groupId>de.ozgcloud</groupId> <artifactId>administration</artifactId> - <version>0.4.0-SNAPSHOT</version> + <version>0.5.0-SNAPSHOT</version> <name>Administration</name> <description>Administration Backend Project</description> diff --git a/src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java b/src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java index d5e5803b9ec8364e3298402bda28c84291a957e4..51fc68105ef225ee93d66f36a448ca4b54c5a9b0 100644 --- a/src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java +++ b/src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java @@ -29,62 +29,70 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.ConstraintViolationException; - import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.ProblemDetail; import org.springframework.security.access.AccessDeniedException; -import org.springframework.web.ErrorResponse; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import de.ozgcloud.common.errorhandling.TechnicalException; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; @RestControllerAdvice public class ExceptionController extends ResponseEntityExceptionHandler { @ExceptionHandler(RuntimeException.class) - public ErrorResponse handleRuntimeException(RuntimeException ex) { - return ErrorResponse.builder(ex, HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage()).build(); + @ResponseBody + public ProblemDetail handleRuntimeException(RuntimeException ex) { + return buildProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex); } @ExceptionHandler(AccessDeniedException.class) - public ErrorResponse handleAccessDeniedException(AccessDeniedException ex) { - return ErrorResponse.builder(ex, HttpStatus.FORBIDDEN, ex.getLocalizedMessage()).build(); + @ResponseBody + public ProblemDetail handleAccessDeniedException(AccessDeniedException ex) { + return buildProblemDetail(HttpStatus.FORBIDDEN, ex); } @ExceptionHandler(ResourceNotFoundException.class) - public ErrorResponse handleResourceNotFoundException(ResourceNotFoundException ex) { - return ErrorResponse.builder(ex, HttpStatus.NOT_FOUND, ex.getLocalizedMessage()).build(); + @ResponseBody + public ProblemDetail handleResourceNotFoundException(ResourceNotFoundException ex) { + return buildProblemDetail(HttpStatus.NOT_FOUND, ex); } @ExceptionHandler(FunctionalException.class) - public ErrorResponse handleFunctionalException(FunctionalException ex) { - return ErrorResponse.builder(ex, HttpStatus.BAD_REQUEST, ex.getLocalizedMessage()).build(); + @ResponseBody + public ProblemDetail handleFunctionalException(FunctionalException ex) { + return buildProblemDetail(HttpStatus.BAD_REQUEST, ex); } @ExceptionHandler(TechnicalException.class) - public ErrorResponse handleTechnicalException(TechnicalException ex) { - return ErrorResponse.builder(ex, HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage()).build(); + @ResponseBody + public ProblemDetail handleTechnicalException(TechnicalException ex) { + return buildProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex); + } + + private ProblemDetail buildProblemDetail(HttpStatus status, Exception ex) { + return ProblemDetail.forStatusAndDetail(status, ex.getLocalizedMessage()); } @ExceptionHandler(ConstraintViolationException.class) - public ErrorResponse handleConstraintViolationException(ConstraintViolationException ex) { - var problemDetail = buildProblemDetail(HttpStatus.UNPROCESSABLE_ENTITY, ex); - return ErrorResponse.builder(ex, problemDetail).build(); + @ResponseBody + public ProblemDetail handleConstraintViolationException(ConstraintViolationException ex) { + return buildConstraintViolationProblemDetail(HttpStatus.UNPROCESSABLE_ENTITY, ex); } - private ProblemDetail buildProblemDetail(HttpStatus status, ConstraintViolationException ex) { + private ProblemDetail buildConstraintViolationProblemDetail(HttpStatus status, ConstraintViolationException ex) { var problemDetail = ProblemDetail.forStatusAndDetail(status, ex.getLocalizedMessage()); problemDetail.setProperty("invalid-params", getDetailedviolationList(ex.getConstraintViolations())); return problemDetail; } private List<Map<String, String>> getDetailedviolationList(Set<ConstraintViolation<?>> violations) { - List<Map<String, String>> detailedViolations = new ArrayList<>(); + var detailedViolations = new ArrayList<Map<String, String>>(); Optional.ofNullable(violations).orElse(Collections.emptySet()).forEach(v -> detailedViolations.add(buildDetailedViolation(v))); return detailedViolations; diff --git a/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java index 18880e1718ab14fcbddfe5663d8a6968740fce20..e965505fc19fda822757ed5b189c88fb9a1d7484 100644 --- a/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java +++ b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java @@ -6,7 +6,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.util.Set; -import java.util.stream.Stream; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; @@ -18,13 +17,9 @@ import org.apache.commons.lang3.StringUtils; import org.assertj.core.util.Arrays; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.HttpStatus; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @@ -47,38 +42,9 @@ class ExceptionControllerITCase { @MockBean private RootModelAssembler modelAssembler; - @Nested - class TestExceptions { - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") - @SneakyThrows - void shouldHandleExceptionWithStatus(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - when(modelAssembler.toModel(any())).thenThrow(TestErrorController.EXCEPTION_PRODUCER.get(exceptionClass).produceException()); - - var result = performGet(); - - result.andExpect(status().is(expectedStatus.value())); - } - - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") - @SneakyThrows - void shouldRespondWithStatusInBody(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - when(modelAssembler.toModel(any())).thenThrow(exceptionClass); - - var result = performGet(); - - result.andExpect(jsonPath("$.status").value(expectedStatus.value())); - } - - private static Stream<Arguments> exceptionAndExpectedStatus() { - return TestErrorController.STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue())); - } - - } - @Nested class TestConstraintViolationException { + @Test @SneakyThrows void shouldHaveInvalidFieldNameInResponse() { @@ -129,11 +95,9 @@ class ExceptionControllerITCase { private String string2; } + @SneakyThrows + private ResultActions performGet() { + return mockMvc.perform(get(RootController.PATH)); + } } - - @SneakyThrows - private ResultActions performGet() { - return mockMvc.perform(get(RootController.PATH)); - } - -} +} \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java index 41f95cf47993da9c9a390d4e7d62702b2f0c79c7..367ed8afd534aa2c443453447e060011b6c1bd22 100644 --- a/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java +++ b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java @@ -21,23 +21,27 @@ */ package de.ozgcloud.admin.common.errorhandling; +import static org.junit.Assert.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -import java.util.stream.Stream; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.jayway.jsonpath.JsonPath; +import de.ozgcloud.common.errorhandling.TechnicalException; import lombok.SneakyThrows; class ExceptionControllerTest { @@ -51,97 +55,392 @@ class ExceptionControllerTest { .setControllerAdvice(new ExceptionController()).build(); } - @DisplayName("Error handler") + @DisplayName("Runtime Exception") @Nested - class TestErrorHandler { + class TestRuntimeException { + + private final static String TEST_ERROR_ENDPOINT = TestErrorController.BASE_PATH + "/runtime"; + private final static int STATUS_VALUE = HttpStatus.INTERNAL_SERVER_ERROR.value(); - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") @SneakyThrows - void shouldHandleExceptionWithStatus(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - var result = doPerformWithError(exceptionClass); + @Test + void shouldReturnStatus() { + var result = doPerformGet(); - result.andExpect(status().is(expectedStatus.value())); + result.andExpect(status().is(STATUS_VALUE)); } - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") - @SneakyThrows - void shouldRespondWithStatusInBody(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - var result = doPerformWithError(exceptionClass); + @DisplayName("response body") + @Nested + class TestRuntimeExceptionBody { + + @SneakyThrows + @Test + void shouldHaveStatus() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.status").value(STATUS_VALUE)); + } + + @SneakyThrows + @Test + void shouldHaveTitle() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.title").value("Internal Server Error")); + } + + @SneakyThrows + @Test + void shouldHaveDetail() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.detail").value("error message")); + } + + @SneakyThrows + @Test + void shouldHaveInstance() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.instance").value(TEST_ERROR_ENDPOINT)); + } - result.andExpect(jsonPath("$.status").value(expectedStatus.value())); + @SneakyThrows + void shouldHaveType() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.type").value("about:blank")); + } } - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") @SneakyThrows - void shouldRespondWithTitler(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - var result = doPerformWithError(exceptionClass); - - result.andExpect(jsonPath("$.title").exists()); + private ResultActions doPerformGet() { + return mockMvc.perform(get(TEST_ERROR_ENDPOINT)); } + } + + @DisplayName("Access Denied Exception") + @Nested + class TestAccessDeniedException { + + private final static String TEST_ERROR_ENDPOINT = TestErrorController.BASE_PATH + "/access-denied"; + private final static int STATUS_VALUE = HttpStatus.FORBIDDEN.value(); - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") @SneakyThrows - void shouldRespondWithDetail(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - var result = doPerformWithError(exceptionClass); + @Test + void shouldReturnStatus() { + var result = doPerformGet(); - result.andExpect(jsonPath("$.detail").exists()); + result.andExpect(status().is(STATUS_VALUE)); } - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") - @SneakyThrows - void shouldRespondWithInstance(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - var result = doPerformWithError(exceptionClass); + @DisplayName("response body") + @Nested + class TestAccessDeniedExceptionBody { + + @SneakyThrows + @Test + void shouldHaveStatus() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.status").value(STATUS_VALUE)); + } + + @SneakyThrows + @Test + void shouldHaveTitle() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.title").value("Forbidden")); + } + + @SneakyThrows + @Test + void shouldHaveDetail() { + var result = doPerformGet(); - result.andExpect(jsonPath("$.instance").exists()); + result.andExpect(jsonPath("$.detail").value("error message")); + } + + @SneakyThrows + @Test + void shouldHaveInstance() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.instance").value(TEST_ERROR_ENDPOINT)); + } + + @SneakyThrows + void shouldHaveType() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.type").value("about:blank")); + } } - @ParameterizedTest - @MethodSource("exceptionAndExpectedStatus") @SneakyThrows - void shouldRespondWithType(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) { - var result = doPerformWithError(exceptionClass); + private ResultActions doPerformGet() { + return mockMvc.perform(get(TEST_ERROR_ENDPOINT)); + } + } - result.andExpect(jsonPath("$.type").exists()); + @DisplayName("ResourceNotFound Exception") + @Nested + class TestResourceNotFoundException { + + private final static String TEST_ERROR_ENDPOINT = TestErrorController.BASE_PATH + "/resource-not-found"; + private final static int STATUS_VALUE = HttpStatus.NOT_FOUND.value(); + + @SneakyThrows + @Test + void shouldReturnStatus() { + var result = doPerformGet(); + + result.andExpect(status().is(STATUS_VALUE)); } - private static Stream<Arguments> exceptionAndExpectedStatus() { - return TestErrorController.STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue())); + @DisplayName("response body") + @Nested + class TestResourceNotFoundExceptionBody { + + @SneakyThrows + @Test + void shouldHaveStatus() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.status").value(STATUS_VALUE)); + } + + @SneakyThrows + @Test + void shouldHaveTitle() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.title").value("Not Found")); + } + + @SneakyThrows + @Test + void shouldHaveDetail() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.detail").value("error message")); + } + + @SneakyThrows + @Test + void shouldHaveInstance() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.instance").value(TEST_ERROR_ENDPOINT)); + } + + @SneakyThrows + void shouldHaveType() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.type").value("about:blank")); + } } @SneakyThrows - private ResultActions doPerformWithError(Class<? extends Exception> exceptionClass) { - return mockMvc.perform(get("/api/test-error").param("errorClassName", exceptionClass.getName())); + private ResultActions doPerformGet() { + return mockMvc.perform(get(TEST_ERROR_ENDPOINT)); } } - @DisplayName("ResourceNotFound error") + @DisplayName("Functional Exception") @Nested - class TestResourceNotFoundError { + class TestFunctionalException { + + private final static String TEST_ERROR_ENDPOINT = TestErrorController.BASE_PATH + "/functional"; + private final static int STATUS_VALUE = HttpStatus.BAD_REQUEST.value(); - @Test @SneakyThrows - void shouldHaveStatus() { - var result = doRequestUnknown(); + @Test + void shouldReturnStatus() { + var result = doPerformGet(); - result.andExpect(status().is(HttpStatus.NOT_FOUND.value())); + result.andExpect(status().is(STATUS_VALUE)); + } + + @DisplayName("response body") + @Nested + class TestFunctionalExceptionBody { + + @SneakyThrows + @Test + void shouldHaveStatus() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.status").value(STATUS_VALUE)); + } + + @SneakyThrows + @Test + void shouldHaveTitle() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.title").value("Bad Request")); + } + + @DisplayName("detail") + @Nested + class TestBodyDetail { + + @SneakyThrows + @Test + void shouldContainErrorMessage() { + var result = doPerformGet(); + + assertTrue(getDetailFromResponseContent(result).contains("Functional error: error message")); + } + + @SneakyThrows + @Test + void shouldContainExceptionId() { + var result = doPerformGet(); + + assertTrue(getDetailFromResponseContent(result).contains("(ExceptionId: ")); + } + } + + @SneakyThrows + @Test + void shouldHaveInstance() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.instance").value(TEST_ERROR_ENDPOINT)); + } + + @SneakyThrows + void shouldHaveType() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.type").value("about:blank")); + } } - @Test @SneakyThrows - void shouldRespondWithStatusInBody() { - var result = doRequestUnknown(); + private ResultActions doPerformGet() { + return mockMvc.perform(get(TEST_ERROR_ENDPOINT)); + } + } + + @DisplayName("TechnicalException") + @Nested + class TestTechnicalException { + + private final static String TEST_ERROR_ENDPOINT = TestErrorController.BASE_PATH + "/technical"; + private final static int STATUS_VALUE = HttpStatus.INTERNAL_SERVER_ERROR.value(); + + @SneakyThrows + @Test + void shouldReturnStatus() { + var result = doPerformGet(); + + result.andExpect(status().is(STATUS_VALUE)); + } + + @DisplayName("response body") + @Nested + class TestTechnicalExceptionBody { - result.andExpect(jsonPath("$.status").value(HttpStatus.NOT_FOUND.value())); + @SneakyThrows + @Test + void shouldHaveStatus() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.status").value(STATUS_VALUE)); + } + + @SneakyThrows + @Test + void shouldHaveTitle() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.title").value("Internal Server Error")); + } + + @DisplayName("detail") + @Nested + class TestBodyDetail { + + @SneakyThrows + @Test + void shouldContainErrorMessage() { + var result = doPerformGet(); + + assertTrue(getDetailFromResponseContent(result).contains("error message")); + } + + @SneakyThrows + @Test + void shouldContainExceptionId() { + var result = doPerformGet(); + + assertTrue(getDetailFromResponseContent(result).contains("(ExceptionId: ")); + } + } + + @SneakyThrows + @Test + void shouldHaveInstance() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.instance").value(TEST_ERROR_ENDPOINT)); + } + + @SneakyThrows + void shouldHaveType() { + var result = doPerformGet(); + + result.andExpect(jsonPath("$.type").value("about:blank")); + } } @SneakyThrows - private ResultActions doRequestUnknown() { - return mockMvc.perform(get("/api/unknown")); + private ResultActions doPerformGet() { + return mockMvc.perform(get(TEST_ERROR_ENDPOINT)); } } + + @SneakyThrows + private String getDetailFromResponseContent(ResultActions resultActions) { + return JsonPath.read(resultActions.andReturn().getResponse().getContentAsString(), "$.detail"); + } } + +@RestController +@RequestMapping(TestErrorController.BASE_PATH) +class TestErrorController { + + public final static String BASE_PATH = "/api/test-error"; + static final String ERROR_MESSAGE = "error message"; + + @GetMapping("/runtime") + String throwRuntimeException() throws Exception { + throw new RuntimeException(ERROR_MESSAGE); + } + + @GetMapping("/access-denied") + String throwAccessException() throws Exception { + throw new AccessDeniedException(ERROR_MESSAGE); + } + + @GetMapping("/resource-not-found") + String throwResourceNotFoundException() throws Exception { + throw new ResourceNotFoundException(ERROR_MESSAGE); + } + + @GetMapping("/functional") + String throwFunctionalExceptionException() throws Exception { + throw new FunctionalException(() -> ERROR_MESSAGE); + } + + @GetMapping("/technical") + String throwTechnicalExceptionException() throws Exception { + throw new TechnicalException(ERROR_MESSAGE); + } +} \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/admin/common/errorhandling/TestErrorController.java b/src/test/java/de/ozgcloud/admin/common/errorhandling/TestErrorController.java deleted file mode 100644 index c49345edcbebd221c8b19ab7fd3e08d11177f4ba..0000000000000000000000000000000000000000 --- a/src/test/java/de/ozgcloud/admin/common/errorhandling/TestErrorController.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2024. Das Land Schleswig-Holstein vertreten durch das Ministerium für Energiewende, Klimaschutz, Umwelt und Natur - * Zentrales IT-Management - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.admin.common.errorhandling; - -import java.util.Collections; -import java.util.Map; - -import jakarta.validation.ConstraintViolationException; - -import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.http.HttpStatus; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import de.ozgcloud.common.errorhandling.TechnicalException; - -@RestController -@RequestMapping("/api/test-error") -class TestErrorController { - - @FunctionalInterface - interface ExceptionProducer { - Exception produceException(); - } - - static final Map<Class<? extends Exception>, HttpStatus> STATUS_BY_EXCEPTION = Map.of( - RuntimeException.class, HttpStatus.INTERNAL_SERVER_ERROR, - AccessDeniedException.class, HttpStatus.FORBIDDEN, - ConstraintViolationException.class, HttpStatus.UNPROCESSABLE_ENTITY, - ResourceNotFoundException.class, HttpStatus.NOT_FOUND, - FunctionalException.class, HttpStatus.BAD_REQUEST, - TechnicalException.class, HttpStatus.INTERNAL_SERVER_ERROR); - - static final String ERROR_MESSAGE = "error message"; - - static Map<Class<? extends Exception>, ExceptionProducer> EXCEPTION_PRODUCER = Map.of( - RuntimeException.class, () -> new RuntimeException(ERROR_MESSAGE), - AccessDeniedException.class, () -> new AccessDeniedException(ERROR_MESSAGE), - ConstraintViolationException.class, () -> new ConstraintViolationException(ERROR_MESSAGE, Collections.emptySet()), - ResourceNotFoundException.class, () -> new ResourceNotFoundException(ERROR_MESSAGE), - FunctionalException.class, () -> new FunctionalException(() -> ERROR_MESSAGE), - TechnicalException.class, () -> new TechnicalException(ERROR_MESSAGE)); - - @GetMapping - String throwException(@RequestParam String errorClassName) throws Exception { - throw EXCEPTION_PRODUCER.get( - Class.forName(errorClassName)).produceException(); - } - -}