From 2bb46476744ea13c7da63878d7cc009fdb59a0f8 Mon Sep 17 00:00:00 2001
From: Colin DAMON <cdamon@ippon.fr>
Date: Mon, 27 Jul 2020 16:42:44 +0200
Subject: [PATCH] Added error handling for query string

---
 .../primary/PouetErrorHandler.java            | 15 ++++++++++
 .../primary/ValidationMessage.java            |  2 ++
 src/main/resources/i18n/messages.properties   |  2 ++
 .../resources/i18n/messages_en.properties     |  2 ++
 .../primary/ErrorsResource.java               |  3 ++
 .../primary/PouetErrorHandlerIntTest.java     | 28 +++++++++++++++++++
 .../primary/QueryParameter.java               | 18 ++++++++++++
 7 files changed, 70 insertions(+)
 create mode 100644 src/test/java/com/ippon/pouet/common/infrastructure/primary/QueryParameter.java

diff --git a/src/main/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandler.java b/src/main/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandler.java
index d152d50..d05bcb5 100644
--- a/src/main/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandler.java
+++ b/src/main/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandler.java
@@ -24,6 +24,7 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.http.converter.HttpMessageNotReadableException;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.validation.BindException;
 import org.springframework.validation.FieldError;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ControllerAdvice;
@@ -178,6 +179,20 @@ public class PouetErrorHandler extends ResponseEntityExceptionHandler {
     return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
   }
 
+  @Override
+  protected ResponseEntity<Object> handleBindException(
+    BindException exception,
+    HttpHeaders headers,
+    HttpStatus status,
+    WebRequest request
+  ) {
+    List<PouetFieldError> fieldErrors = exception.getFieldErrors().stream().map(toPouetFieldError()).collect(Collectors.toList());
+
+    PouetError error = new PouetError(BAD_REQUEST_KEY, getMessage(BAD_REQUEST_KEY, null), fieldErrors);
+
+    return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
+  }
+
   @ExceptionHandler
   public ResponseEntity<PouetError> handleBeanValidationError(ConstraintViolationException exception) {
     logger.debug("Bean validation error {}", exception.getMessage(), exception);
diff --git a/src/main/java/com/ippon/pouet/common/infrastructure/primary/ValidationMessage.java b/src/main/java/com/ippon/pouet/common/infrastructure/primary/ValidationMessage.java
index b7e0230..f8d1da3 100644
--- a/src/main/java/com/ippon/pouet/common/infrastructure/primary/ValidationMessage.java
+++ b/src/main/java/com/ippon/pouet/common/infrastructure/primary/ValidationMessage.java
@@ -3,6 +3,8 @@ package com.ippon.pouet.common.infrastructure.primary;
 public final class ValidationMessage {
   public static final String MANDATORY = "user.mandatory";
   public static final String WRONG_FORMAT = "user.wrong-format";
+  public static final String VALUE_TOO_LOW = "user.too-low";
+  public static final String VALUE_TOO_HIGH = "user.too-high";
 
   private ValidationMessage() {}
 }
diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties
index 4be83a1..dbd8c49 100644
--- a/src/main/resources/i18n/messages.properties
+++ b/src/main/resources/i18n/messages.properties
@@ -29,6 +29,8 @@ pouet.error.status-exception=Une erreur {{ status }} est survenue lors du traite
 pouet.error.user.bad-request=Les données que vous avez saisies sont incorrectes.
 pouet.error.user.mandatory=Le champ est obligatoire.
 pouet.error.user.wrong-format=Le format n'est pas correct, il doit respecter "{{ regexp }}".
+pouet.error.user.too-low=La valeur que vous avez entrée est trop petite, le minimum autorisé est {{ value }}.
+pouet.error.user.too-high=La valeur que vous avez entrée est trop grande, le maximum autorisé est {{ value }}.
 pouet.error.user.authentication-not-authenticated=Vous devez être authentifié pour acceder à cette ressource.
 pouet.error.user.access-denied=Vous n'avez pas les droits suffisants pour acceder à cette ressource.
 pouet.error.user.e-mail-already-used=Cette adresse email est déjà utilisée dans pouet.
diff --git a/src/main/resources/i18n/messages_en.properties b/src/main/resources/i18n/messages_en.properties
index 519e397..e28c5af 100644
--- a/src/main/resources/i18n/messages_en.properties
+++ b/src/main/resources/i18n/messages_en.properties
@@ -29,6 +29,8 @@ pouet.error.status-exception=An error {{ status }} occured while handling your r
 pouet.error.user.bad-request=The values you entered are incorrects.
 pouet.error.user.mandatory=The field is mandatory.
 pouet.error.user.wrong-format=The format is incorrect, it has to match "{{ regexp }}".
+pouet.error.user.too-low=The value you entered is too low, minimum autorized is {{ value }}.
+pouet.error.user.too-high=The value you entered is too high, maximum authorized is {{ value }}.
 pouet.error.user.authentication-not-authenticated=You must be authenticated to access this resource.
 pouet.error.user.access-denied=You don't have sufficient rights to access this resource.
 pouet.error.user.e-mail-already-used=This email address is already used in the pouet.
diff --git a/src/test/java/com/ippon/pouet/common/infrastructure/primary/ErrorsResource.java b/src/test/java/com/ippon/pouet/common/infrastructure/primary/ErrorsResource.java
index 4baa1f0..57eb076 100644
--- a/src/test/java/com/ippon/pouet/common/infrastructure/primary/ErrorsResource.java
+++ b/src/test/java/com/ippon/pouet/common/infrastructure/primary/ErrorsResource.java
@@ -57,6 +57,9 @@ class ErrorsResource {
     throw new ResponseStatusException(HttpStatus.NOT_FOUND);
   }
 
+  @GetMapping
+  public void queryStringWithRangedValue(@Validated QueryParameter parameter) {}
+
   @GetMapping("/{complicated}")
   public void complicatedArg(
     @Validated @Pattern(message = ValidationMessage.WRONG_FORMAT, regexp = "complicated") @PathVariable("complicated") String complicated
diff --git a/src/test/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandlerIntTest.java b/src/test/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandlerIntTest.java
index 12c223e..1e18521 100644
--- a/src/test/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandlerIntTest.java
+++ b/src/test/java/com/ippon/pouet/common/infrastructure/primary/PouetErrorHandlerIntTest.java
@@ -111,6 +111,34 @@ class PouetErrorHandlerIntTest {
       .contains("Le format n'est pas correct, il doit respecter \\\"complicated\\\".");
   }
 
+  @Test
+  public void shouldMapMinValueQueryStringBeanValidationErrors() throws Exception {
+    String response = mockMvc
+      .perform(get(errorEndpoint("?parameter=1")).header(HttpHeaders.ACCEPT_LANGUAGE, FRANCE_TAG))
+      .andExpect(status().isBadRequest())
+      .andReturn()
+      .getResponse()
+      .getContentAsString(UTF_8);
+
+    assertThat(response)
+      .contains("Les données que vous avez saisies sont incorrectes.")
+      .contains("La valeur que vous avez entrée est trop petite, le minimum autorisé est 42.");
+  }
+
+  @Test
+  public void shouldMapMaxValueQueryStringBeanValidationErrors() throws Exception {
+    String response = mockMvc
+      .perform(get(errorEndpoint("?parameter=100")).header(HttpHeaders.ACCEPT_LANGUAGE, FRANCE_TAG))
+      .andExpect(status().isBadRequest())
+      .andReturn()
+      .getResponse()
+      .getContentAsString(UTF_8);
+
+    assertThat(response)
+      .contains("Les données que vous avez saisies sont incorrectes.")
+      .contains("La valeur que vous avez entrée est trop grande, le maximum autorisé est 42.");
+  }
+
   @Test
   public void shouldMapBodyBeanValidationErrors() throws Exception {
     String response = mockMvc
diff --git a/src/test/java/com/ippon/pouet/common/infrastructure/primary/QueryParameter.java b/src/test/java/com/ippon/pouet/common/infrastructure/primary/QueryParameter.java
new file mode 100644
index 0000000..bb284b5
--- /dev/null
+++ b/src/test/java/com/ippon/pouet/common/infrastructure/primary/QueryParameter.java
@@ -0,0 +1,18 @@
+package com.ippon.pouet.common.infrastructure.primary;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
+class QueryParameter {
+  private int parameter;
+
+  @Min(message = ValidationMessage.VALUE_TOO_LOW, value = 42)
+  @Max(message = ValidationMessage.VALUE_TOO_HIGH, value = 42)
+  public int getParameter() {
+    return parameter;
+  }
+
+  public void setParameter(int parameter) {
+    this.parameter = parameter;
+  }
+}
-- 
GitLab