Added a working @ExceptionHandler
authorKai Moritz <kai@juplo.de>
Sat, 19 Sep 2020 10:46:52 +0000 (12:46 +0200)
committerKai Moritz <kai@juplo.de>
Sat, 3 Oct 2020 10:34:07 +0000 (12:34 +0200)
* Both handlers resolve the handled exception as 503 Internal Server Error
  and are using the template "error/503", which was extended to print a
  message, that the reported exception was catched and handled.
* If one starts the app, it is clearly visible, that the mechanism only
  works for exceptions, that are thrown in the context of the controller.
* Also added a test-case, that shows, that MockMvc shows the expected
  behaviour for exceptions, that are thrown inside the container.

src/main/java/de/juplo/demo/ExampleController.java
src/main/java/de/juplo/demo/ExampleService.java
src/main/resources/templates/400.html [new file with mode: 0644]
src/test/java/de/juplo/demo/ExceptionHandlingApplicationTests.java

index de806ef..a6efeb2 100644 (file)
@@ -7,6 +7,7 @@ import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.ModelAndView;
 import org.thymeleaf.exceptions.TemplateProcessingException;
 
 import java.util.Optional;
@@ -41,6 +42,16 @@ public class ExampleController
         return "view";
     }
 
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(IllegalArgumentException.class)
+    public ModelAndView illegalArgumentException(IllegalArgumentException e)
+    {
+        LOG.error("{}: {}", HttpStatus.BAD_REQUEST, e.getMessage());
+        ModelAndView mav = new ModelAndView("400");
+        mav.addObject("exception", e);
+        return mav;
+    }
+
     /**
      * This {@link ExceptionHandler @ExceptionHander} is never triggered,
      * because the exception is not thrown inside the controller:
@@ -59,9 +70,12 @@ public class ExampleController
      */
     @ResponseStatus(HttpStatus.BAD_REQUEST)
     @ExceptionHandler(TemplateProcessingException.class)
-    public void templateInputException(TemplateProcessingException e)
+    public ModelAndView templateInputException(TemplateProcessingException e)
     {
         LOG.error("{}: {}", HttpStatus.BAD_REQUEST, e.getMessage());
+        ModelAndView mav = new ModelAndView("400");
+        mav.addObject("exception", e);
+        return mav;
     }
 }
 
index ec21629..45f2ca1 100644 (file)
@@ -13,8 +13,14 @@ public class ExampleService
             return Optional.empty();
 
         if (answer == 42)
+        {
             return Optional.of(true);
+        }
         else
+        {
+            if (answer % 7 == 0)
+                throw new IllegalArgumentException(answer + " is devidable by 7!");
             return Optional.of(false);
+        }
     }
 }
diff --git a/src/main/resources/templates/400.html b/src/main/resources/templates/400.html
new file mode 100644 (file)
index 0000000..f1d4d5d
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html xmlns:th="http://www.thymeleaf.org">
+  <head>
+    <title th:text="'400: ' + ${exception.getClass().getSimpleName()}">Testing Exception-Handling - Template for 400</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+  <body>
+    <h1 th:text="'400: ' + ${exception.getClass().getSimpleName()}">Template for 400</h1>
+    <div>
+      <p><strong th:text="'Catched exception: ' + ${exception}">EXCEPTION</strong></p>
+      <p><a href="#" th:href="@{/}">Back to HOME</a></p>
+    </div>
+  </body>
+</html>
index c9a4d49..62f3a13 100644 (file)
@@ -140,4 +140,23 @@ class ExceptionHandlingApplicationTests {
 
                verify(service, times(0)).checkAnswer(anyInt());
        }
+
+       @Test
+       void test400ForExceptionInBusinessLogic() throws Exception {
+               when(service.checkAnswer(anyInt())).thenThrow(new IllegalArgumentException("FOO!"));
+
+               mvc
+                               .perform(get(URI.create("http://FOO/?answer=1234")))
+                               .andExpect(status().isBadRequest())
+                               .andDo((result) -> {
+                                       String content = result.getResponse().getContentAsString();
+                                       Document doc = Jsoup.parse(content);
+                                       assertThat(doc.selectFirst("title").text())
+                                                       .isEqualTo("400: IllegalArgumentException");
+                                       assertThat(doc.selectFirst("div > p > strong").text())
+                                                       .isEqualTo("Catched exception: java.lang.IllegalArgumentException: FOO!");
+                               });
+
+               verify(service, times(1)).checkAnswer(anyInt());
+       }
 }