11/*
2- * Copyright 2002-2018 the original author or authors.
2+ * Copyright 2002-2020 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1818
1919import org .junit .Test ;
2020
21+ import org .springframework .core .Ordered ;
22+ import org .springframework .core .annotation .Order ;
23+ import org .springframework .http .MediaType ;
2124import org .springframework .stereotype .Controller ;
2225import org .springframework .web .bind .annotation .ControllerAdvice ;
2326import org .springframework .web .bind .annotation .ExceptionHandler ;
2427import org .springframework .web .bind .annotation .GetMapping ;
2528import org .springframework .web .bind .annotation .PathVariable ;
29+ import org .springframework .web .bind .annotation .RestController ;
30+ import org .springframework .web .bind .annotation .RestControllerAdvice ;
2631
2732import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .*;
2833import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .*;
3237 * Exception handling via {@code @ExceptionHandler} method.
3338 *
3439 * @author Rossen Stoyanchev
40+ * @author Sam Brannen
3541 */
3642public class ExceptionHandlerTests {
3743
3844 @ Test
39- public void testExceptionHandlerMethod () throws Exception {
45+ public void mvcLocalExceptionHandlerMethod () throws Exception {
4046 standaloneSetup (new PersonController ()).build ()
41- .perform (get ("/person/Clyde" ))
47+ .perform (get ("/person/Clyde" ))
4248 .andExpect (status ().isOk ())
4349 .andExpect (forwardedUrl ("errorView" ));
4450 }
4551
4652 @ Test
47- public void testGlobalExceptionHandlerMethod () throws Exception {
53+ public void mvcGlobalExceptionHandlerMethod () throws Exception {
4854 standaloneSetup (new PersonController ()).setControllerAdvice (new GlobalExceptionHandler ()).build ()
4955 .perform (get ("/person/Bonnie" ))
5056 .andExpect (status ().isOk ())
5157 .andExpect (forwardedUrl ("globalErrorView" ));
5258 }
5359
5460 @ Test
55- public void testGlobalExceptionHandlerMethodUsingClassArgument () throws Exception {
61+ public void mvcGlobalExceptionHandlerMethodUsingClassArgument () throws Exception {
5662 standaloneSetup (PersonController .class ).setControllerAdvice (GlobalExceptionHandler .class ).build ()
5763 .perform (get ("/person/Bonnie" ))
5864 .andExpect (status ().isOk ())
5965 .andExpect (forwardedUrl ("globalErrorView" ));
6066 }
6167
68+ @ Test
69+ public void restNoException () throws Exception {
70+ standaloneSetup (RestPersonController .class )
71+ .setControllerAdvice (RestGlobalExceptionHandler .class , RestPersonControllerExceptionHandler .class ).build ()
72+ .perform (get ("/person/Yoda" ).accept (MediaType .APPLICATION_JSON ))
73+ .andExpect (status ().isOk ())
74+ .andExpect (jsonPath ("$.name" ).value ("Yoda" ));
75+ }
76+
77+ @ Test
78+ public void restLocalExceptionHandlerMethod () throws Exception {
79+ standaloneSetup (RestPersonController .class )
80+ .setControllerAdvice (RestGlobalExceptionHandler .class , RestPersonControllerExceptionHandler .class ).build ()
81+ .perform (get ("/person/Luke" ).accept (MediaType .APPLICATION_JSON ))
82+ .andExpect (status ().isOk ())
83+ .andExpect (jsonPath ("$.error" ).value ("local - IllegalArgumentException" ));
84+ }
85+
86+ @ Test
87+ public void restGlobalExceptionHandlerMethod () throws Exception {
88+ standaloneSetup (RestPersonController .class )
89+ .setControllerAdvice (RestGlobalExceptionHandler .class ).build ()
90+ .perform (get ("/person/Leia" ).accept (MediaType .APPLICATION_JSON ))
91+ .andExpect (status ().isOk ())
92+ .andExpect (jsonPath ("$.error" ).value ("global - IllegalStateException" ));
93+ }
94+
95+ @ Test
96+ public void restGlobalRestPersonControllerExceptionHandlerTakesPrecedenceOverGlobalExceptionHandler () throws Exception {
97+ standaloneSetup (RestPersonController .class )
98+ .setControllerAdvice (RestGlobalExceptionHandler .class , RestPersonControllerExceptionHandler .class ).build ()
99+ .perform (get ("/person/Leia" ).accept (MediaType .APPLICATION_JSON ))
100+ .andExpect (status ().isOk ())
101+ .andExpect (jsonPath ("$.error" ).value ("globalPersonController - IllegalStateException" ));
102+ }
103+
104+ @ Test // gh-25520
105+ public void restNoHandlerFound () throws Exception {
106+ standaloneSetup (RestPersonController .class )
107+ .setControllerAdvice (RestGlobalExceptionHandler .class , RestPersonControllerExceptionHandler .class )
108+ .addDispatcherServletCustomizer (dispatcherServlet -> dispatcherServlet .setThrowExceptionIfNoHandlerFound (true ))
109+ .build ()
110+ .perform (get ("/bogus" ).accept (MediaType .APPLICATION_JSON ))
111+ .andExpect (status ().isOk ())
112+ .andExpect (jsonPath ("$.error" ).value ("global - NoHandlerFoundException" ));
113+ }
114+
62115
63116 @ Controller
64117 private static class PersonController {
@@ -80,15 +133,80 @@ public String handleException(IllegalArgumentException exception) {
80133 }
81134 }
82135
83-
84136 @ ControllerAdvice
85137 private static class GlobalExceptionHandler {
86138
87139 @ ExceptionHandler
88140 public String handleException (IllegalStateException exception ) {
89141 return "globalErrorView" ;
90142 }
143+ }
144+
145+ @ RestController
146+ private static class RestPersonController {
147+
148+ @ GetMapping ("/person/{name}" )
149+ Person get (@ PathVariable String name ) {
150+ switch (name ) {
151+ case "Luke" :
152+ throw new IllegalArgumentException ();
153+ case "Leia" :
154+ throw new IllegalStateException ();
155+ default :
156+ return new Person ("Yoda" );
157+ }
158+ }
91159
160+ @ ExceptionHandler
161+ Error handleException (IllegalArgumentException exception ) {
162+ return new Error ("local - " + exception .getClass ().getSimpleName ());
163+ }
164+ }
165+
166+ @ RestControllerAdvice (assignableTypes = RestPersonController .class )
167+ @ Order (Ordered .HIGHEST_PRECEDENCE )
168+ private static class RestPersonControllerExceptionHandler {
169+
170+ @ ExceptionHandler
171+ Error handleException (Throwable exception ) {
172+ return new Error ("globalPersonController - " + exception .getClass ().getSimpleName ());
173+ }
174+ }
175+
176+ @ RestControllerAdvice
177+ @ Order (Ordered .LOWEST_PRECEDENCE )
178+ private static class RestGlobalExceptionHandler {
179+
180+ @ ExceptionHandler
181+ Error handleException (Throwable exception ) {
182+ return new Error ( "global - " + exception .getClass ().getSimpleName ());
183+ }
184+ }
185+
186+ static class Person {
187+
188+ private final String name ;
189+
190+ Person (String name ) {
191+ this .name = name ;
192+ }
193+
194+ public String getName () {
195+ return name ;
196+ }
197+ }
198+
199+ static class Error {
200+
201+ private final String error ;
202+
203+ Error (String error ) {
204+ this .error = error ;
205+ }
206+
207+ public String getError () {
208+ return error ;
209+ }
92210 }
93211
94212}
0 commit comments