Skip to content

Commit 3b7691d

Browse files
committed
SPR-6008 - @ResponseStatus on @ExceptionHandler method is ignored
1 parent 5680cd4 commit 3b7691d

File tree

3 files changed

+35
-10
lines changed

3 files changed

+35
-10
lines changed

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.util.ObjectUtils;
4545
import org.springframework.util.ReflectionUtils;
4646
import org.springframework.web.bind.annotation.ExceptionHandler;
47+
import org.springframework.web.bind.annotation.ResponseStatus;
4748
import org.springframework.web.bind.support.WebArgumentResolver;
4849
import org.springframework.web.context.request.NativeWebRequest;
4950
import org.springframework.web.context.request.ServletWebRequest;
@@ -89,14 +90,14 @@ protected ModelAndView doResolveException(HttpServletRequest request,
8990
if (handler != null) {
9091
Method handlerMethod = findBestExceptionHandlerMethod(handler, ex);
9192
if (handlerMethod != null) {
92-
NativeWebRequest webRequest = new ServletWebRequest(request, response);
93+
ServletWebRequest webRequest = new ServletWebRequest(request, response);
9394
try {
9495
Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, ex);
9596
if (logger.isDebugEnabled()) {
9697
logger.debug("Invoking request handler method: " + handlerMethod);
9798
}
9899
Object retVal = doInvokeMethod(handlerMethod, handler, args);
99-
return getModelAndView(retVal);
100+
return getModelAndView(handlerMethod, handler.getClass(), retVal, webRequest);
100101
}
101102
catch (Exception invocationEx) {
102103
logger.error("Invoking request method resulted in exception : " + handlerMethod, invocationEx);
@@ -109,7 +110,7 @@ protected ModelAndView doResolveException(HttpServletRequest request,
109110
/**
110111
* Finds the handler method that matches the thrown exception best.
111112
*
112-
* @param handler the handler object
113+
* @param handler the handler object
113114
* @param thrownException the exception to be handled
114115
* @return the best matching method; or <code>null</code> if none is found
115116
*/
@@ -171,7 +172,9 @@ protected List<Class<? extends Throwable>> getHandledExceptions(Method method) {
171172
return result;
172173
}
173174

174-
/** Returns the best matching method. Uses the {@link DepthComparator}. */
175+
/**
176+
* Returns the best matching method. Uses the {@link DepthComparator}.
177+
*/
175178
private Method getBestMatchingMethod(Exception thrownException,
176179
Map<Class<? extends Throwable>, Method> resolverMethods) {
177180
if (!resolverMethods.isEmpty()) {
@@ -186,7 +189,9 @@ private Method getBestMatchingMethod(Exception thrownException,
186189
}
187190
}
188191

189-
/** Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. */
192+
/**
193+
* Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}.
194+
*/
190195
private Object[] resolveHandlerArguments(Method handlerMethod,
191196
Object handler,
192197
NativeWebRequest webRequest,
@@ -221,7 +226,7 @@ private Object[] resolveHandlerArguments(Method handlerMethod,
221226
* then checking {@link #resolveStandardArgument}.
222227
*
223228
* @param methodParameter the method parameter
224-
* @param webRequest the request
229+
* @param webRequest the request
225230
* @param thrownException the exception thrown
226231
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
227232
*/
@@ -256,8 +261,8 @@ protected Object resolveCommonArgument(MethodParameter methodParameter,
256261
* request {@link InputStream}, request {@link Reader}, response {@link OutputStream}, response {@link Writer},
257262
* and the given {@code thrownException}.
258263
*
259-
* @param parameterType the method parameter type
260-
* @param webRequest the request
264+
* @param parameterType the method parameter type
265+
* @param webRequest the request
261266
* @param thrownException the exception thrown
262267
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
263268
*/
@@ -319,7 +324,16 @@ private Object doInvokeMethod(Method method, Object target, Object[] args) throw
319324
}
320325

321326
@SuppressWarnings("unchecked")
322-
private ModelAndView getModelAndView(Object returnValue) {
327+
private ModelAndView getModelAndView(Method handlerMethod,
328+
Class handlerType,
329+
Object returnValue,
330+
ServletWebRequest webRequest) throws Exception {
331+
332+
if (handlerMethod.isAnnotationPresent(ResponseStatus.class)) {
333+
ResponseStatus responseStatus = handlerMethod.getAnnotation(ResponseStatus.class);
334+
HttpServletResponse response = webRequest.getResponse();
335+
response.setStatus(responseStatus.value().value());
336+
}
323337
if (returnValue instanceof ModelAndView) {
324338
return (ModelAndView) returnValue;
325339
}
@@ -343,7 +357,9 @@ else if (returnValue == null) {
343357
}
344358
}
345359

346-
/** Comparator capable of sorting exceptions based on their depth from the thrown exception type. */
360+
/**
361+
* Comparator capable of sorting exceptions based on their depth from the thrown exception type.
362+
*/
347363
private static class DepthComparator implements Comparator<Class<? extends Throwable>> {
348364

349365
private final Class<? extends Throwable> handlerExceptionType;

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolverTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import org.springframework.stereotype.Controller;
3131
import org.springframework.util.ClassUtils;
3232
import org.springframework.web.bind.annotation.ExceptionHandler;
33+
import org.springframework.web.bind.annotation.ResponseStatus;
3334
import org.springframework.web.servlet.ModelAndView;
35+
import org.springframework.http.HttpStatus;
3436

3537
/** @author Arjen Poutsma */
3638
public class AnnotationMethodHandlerExceptionResolverTests {
@@ -56,6 +58,8 @@ public void simple() {
5658
ModelAndView mav = exceptionResolver.resolveException(request, response, controller, ex);
5759
assertNotNull("No ModelAndView returned", mav);
5860
assertEquals("Invalid view name returned", "BindException", mav.getViewName());
61+
assertEquals("Invalid status code returned", 406, response.getStatus());
62+
5963
}
6064

6165
@Test(expected = IllegalStateException.class)
@@ -74,6 +78,7 @@ public String handleIOException(IOException ex, HttpServletRequest request) {
7478
}
7579

7680
@ExceptionHandler(BindException.class)
81+
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
7782
public String handleBindException(Exception ex, HttpServletResponse response) {
7883
return ClassUtils.getShortName(ex.getClass());
7984
}

org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@
8383
* only applicable in a Servlet environment).
8484
* </ul>
8585
*
86+
* <p>In Servlet environments, you can combine the {@code ExceptionHandler} annotation
87+
* with {@link ResponseStatus @ResponseStatus}, to define the response status
88+
* for the HTTP response.
89+
*
8690
* <p><b>NOTE: <code>@RequestMapping</code> will only be processed if a
8791
* corresponding <code>HandlerMapping</code> (for type level annotations)
8892
* and/or <code>HandlerAdapter</code> (for method level annotations) is

0 commit comments

Comments
 (0)