From 88ad86e5ea3131b742deb468f5e557d58097c22e Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Fri, 20 Sep 2024 09:21:57 +0200 Subject: [PATCH 1/2] feat: Allow override of the `message` property for a violation exception Fixes #103 --- .../ConstraintViolationApiExceptionHandler.java | 10 +++++----- .../mapper/ErrorMessageMapper.java | 6 ++++++ ...ConstraintViolationApiExceptionHandlerTest.java | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandler.java b/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandler.java index 1960ab9..cd7c048 100644 --- a/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandler.java +++ b/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandler.java @@ -4,14 +4,13 @@ import io.github.wimdeblauwe.errorhandlingspringbootstarter.mapper.ErrorCodeMapper; import io.github.wimdeblauwe.errorhandlingspringbootstarter.mapper.ErrorMessageMapper; import io.github.wimdeblauwe.errorhandlingspringbootstarter.mapper.HttpStatusMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; - import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import jakarta.validation.ElementKind; import jakarta.validation.Path; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; import java.util.Comparator; import java.util.Optional; @@ -136,6 +135,7 @@ private String getMessage(ConstraintViolation constraintViolation) { } private String getMessage(ConstraintViolationException exception) { - return "Validation failed. Error count: " + exception.getConstraintViolations().size(); + return errorMessageMapper.getErrorMessageIfConfiguredInProperties(exception) + .orElseGet(() -> "Validation failed. Error count: " + exception.getConstraintViolations().size()); } } diff --git a/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/mapper/ErrorMessageMapper.java b/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/mapper/ErrorMessageMapper.java index f87c7d3..98e5d3d 100644 --- a/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/mapper/ErrorMessageMapper.java +++ b/src/main/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/mapper/ErrorMessageMapper.java @@ -2,6 +2,8 @@ import io.github.wimdeblauwe.errorhandlingspringbootstarter.ErrorHandlingProperties; +import java.util.Optional; + import static org.springframework.util.StringUtils.hasText; /** @@ -22,6 +24,10 @@ public String getErrorMessage(Throwable exception) { return exception.getMessage(); } + public Optional getErrorMessageIfConfiguredInProperties(Throwable exception) { + return Optional.ofNullable(getErrorMessageFromProperties(exception.getClass())); + } + public String getErrorMessage(String fieldSpecificCode, String code, String defaultMessage) { if (properties.getMessages().containsKey(fieldSpecificCode)) { return properties.getMessages().get(fieldSpecificCode); diff --git a/src/test/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandlerTest.java b/src/test/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandlerTest.java index 7773ec3..b2d95f0 100644 --- a/src/test/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandlerTest.java +++ b/src/test/java/io/github/wimdeblauwe/errorhandlingspringbootstarter/handler/ConstraintViolationApiExceptionHandlerTest.java @@ -110,6 +110,20 @@ void testErrorCodeOverride(@Autowired ErrorHandlingProperties properties) throws ; } + @Test + @WithMockUser + void testErrorMessageOverride(@Autowired ErrorHandlingProperties properties) throws Exception { + properties.getMessages().put("jakarta.validation.ConstraintViolationException", "There was a validation failure."); + mockMvc.perform(post("/test/validation") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"value2\": \"\"}") + .with(csrf())) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("code").value("VALIDATION_FAILED")) + .andExpect(jsonPath("message").value("There was a validation failure.")) + ; + } + @Test @WithMockUser void testFieldErrorCodeOverride(@Autowired ErrorHandlingProperties properties) throws Exception { From 7236fc6e07f135dd5e879303cda8c9827a6a48b8 Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Tue, 24 Sep 2024 22:06:52 +0200 Subject: [PATCH 2/2] docs: Add documentation on how to override the message of an exception Fixes #103 --- src/docs/asciidoc/index.adoc | 54 ++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index e4fa213..5d7c4cc 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -472,8 +472,58 @@ The response JSON: ==== General override of error messages -By using `error.handling.messages` property, it is possible to globally set an error message for a certain exception. -This is most useful for the validation messages. +By using `error.handling.messages` property, it is possible to globally set an error message for a certain exception or a certain validation annotation. + +===== Exception + +Suppose you have this defined: + +[source,properties] +---- +error.handling.messages.com.company.application.user.UserNotFoundException=The user was not found +---- + +The response JSON: + +[source,json] +---- +{ + "code": "USER_NOT_FOUND", + "message": "The user was not found" //<.> +} +---- + +<.> The output uses the configured override. + +This can also be used for exception types that are not part of your own application. + +For example: + +[source,properties] +---- +error.handling.messages.jakarta.validation.ConstraintViolationException=There was a validation failure. +---- + +Will output the following JSON: + +[source,json] +---- +{ + "code": "VALIDATION_FAILED", + "message": "There was a validation failure.", + "fieldErrors": [ + { + "code": "INVALID_SIZE", + "property": "name", + "message": "size must be between 10 and 2147483647", + "rejectedValue": "", + "path": "name" + } + ] +} +---- + +===== Validation annotation Suppose you have this defined: