@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2015 the original author or authors .
* Copyright 2002 - 2016 the original author or authors .
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
@ -16,6 +16,7 @@
@@ -16,6 +16,7 @@
package org.springframework.web.servlet.mvc.annotation ;
import java.io.IOException ;
import javax.servlet.http.HttpServletRequest ;
import javax.servlet.http.HttpServletResponse ;
@ -25,6 +26,7 @@ import org.springframework.context.i18n.LocaleContextHolder;
@@ -25,6 +26,7 @@ import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.annotation.AnnotatedElementUtils ;
import org.springframework.util.StringUtils ;
import org.springframework.web.bind.annotation.ResponseStatus ;
import org.springframework.web.server.ResponseStatusException ;
import org.springframework.web.servlet.ModelAndView ;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver ;
@ -41,6 +43,8 @@ import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
@@ -41,6 +43,8 @@ import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
* present on cause exceptions , and as of 4 . 2 . 2 this resolver supports
* attribute overrides for { @code @ResponseStatus } in custom composed annotations .
*
* < p > As of 5 . 0 this resolver also supports { @link ResponseStatusException } .
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Sam Brannen
@ -62,43 +66,80 @@ public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionRes
@@ -62,43 +66,80 @@ public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionRes
protected ModelAndView doResolveException ( HttpServletRequest request , HttpServletResponse response ,
Object handler , Exception ex ) {
ResponseStatus responseStatus = AnnotatedElementUtils . findMergedAnnotation ( ex . getClass ( ) , ResponseStatus . class ) ;
if ( responseStatus ! = null ) {
try {
return resolveResponseStatus ( responseStatus , request , response , handler , ex ) ;
}
catch ( Exception resolveEx ) {
logger . warn ( "Handling of @ResponseStatus resulted in Exception" , resolveEx ) ;
if ( ex instanceof ResponseStatusException ) {
return resolveResponseStatusException ( ( ResponseStatusException ) ex , request , response , handler ) ;
}
ResponseStatus status = AnnotatedElementUtils . findMergedAnnotation ( ex . getClass ( ) , ResponseStatus . class ) ;
if ( status ! = null ) {
return resolveResponseStatus ( status , request , response , handler , ex ) ;
}
else if ( ex . getCause ( ) instanceof Exception ) {
if ( ex . getCause ( ) instanceof Exception ) {
ex = ( Exception ) ex . getCause ( ) ;
return doResolveException ( request , response , handler , ex ) ;
}
}
catch ( Exception resolveEx ) {
logger . warn ( "Handling of @ResponseStatus resulted in Exception" , resolveEx ) ;
}
return null ;
}
/ * *
* Template method that handles { @link ResponseStatus @ResponseStatus } annotation .
* < p > The default implementation sends a response error using
* { @link HttpServletResponse # sendError ( int ) } or
* { @link HttpServletResponse # sendError ( int , String ) } if the annotation has a
* { @linkplain ResponseStatus # reason ( ) reason } and then returns an empty ModelAndView .
* @param responseStatus the annotation
* Template method that handles the { @link ResponseStatus @ResponseStatus } annotation .
* < p > The default implementation delegates to { @link # applyStatusAndReason }
* with the status code and reason from the annotation .
* @param responseStatus the { @code @ResponseStatus } annotation
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler , or { @code null } if none chosen at the
* time of the exception ( for example , if multipart resolution failed )
* @param ex the exception that got thrown during handler execution or the
* exception that has the ResponseStatus annotation if found on the cause .
* @return a corresponding ModelAndView to forward to , or { @code null }
* for default processing
* time of the exception , e . g . if multipart resolution failed
* @param ex the exception
* @return an empty ModelAndView , i . e . exception resolved
* /
protected ModelAndView resolveResponseStatus ( ResponseStatus responseStatus , HttpServletRequest request ,
HttpServletResponse response , Object handler , Exception ex ) throws Exception {
protected ModelAndView resolveResponseStatus ( ResponseStatus responseStatus ,
HttpServletRequest request , HttpServletResponse response , Object handler , Exception ex )
throws Exception {
int statusCode = responseStatus . code ( ) . value ( ) ;
String reason = responseStatus . reason ( ) ;
return applyStatusAndReason ( statusCode , reason , response ) ;
}
/ * *
* Template method that handles an { @link ResponseStatusException } .
* < p > The default implementation delegates to { @link # applyStatusAndReason }
* with the status code and reason from the exception .
* @param ex the exception
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler , or { @code null } if none chosen at the
* time of the exception , e . g . if multipart resolution failed
* @return an empty ModelAndView , i . e . exception resolved
* @since 5 . 0
* /
protected ModelAndView resolveResponseStatusException ( ResponseStatusException ex ,
HttpServletRequest request , HttpServletResponse response , Object handler ) throws Exception {
int statusCode = ex . getStatus ( ) . value ( ) ;
String reason = ex . getReason ( ) ;
applyStatusAndReason ( statusCode , reason , response ) ;
return new ModelAndView ( ) ;
}
/ * *
* Apply the resolved status code and reason to the response .
* < p > The default implementation sends a response error using
* { @link HttpServletResponse # sendError ( int ) } or
* { @link HttpServletResponse # sendError ( int , String ) } if there is a reason
* and then returns an empty ModelAndView .
* @since 5 . 0
* /
protected ModelAndView applyStatusAndReason ( int statusCode , String reason , HttpServletResponse response )
throws IOException {
if ( this . messageSource ! = null ) {
reason = this . messageSource . getMessage ( reason , null , reason , LocaleContextHolder . getLocale ( ) ) ;
}