@ -15,7 +15,6 @@
@@ -15,7 +15,6 @@
* /
package org.springframework.web.servlet.mvc.method.annotation ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Set ;
@ -28,6 +27,7 @@ import org.springframework.http.HttpMethod;
@@ -28,6 +27,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus ;
import org.springframework.http.MediaType ;
import org.springframework.http.ResponseEntity ;
import org.springframework.http.converter.HttpMessageConverter ;
import org.springframework.http.converter.HttpMessageNotReadableException ;
import org.springframework.http.converter.HttpMessageNotWritableException ;
import org.springframework.util.CollectionUtils ;
@ -40,30 +40,34 @@ import org.springframework.web.bind.MissingServletRequestParameterException;
@@ -40,30 +40,34 @@ import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException ;
import org.springframework.web.bind.annotation.ControllerAdvice ;
import org.springframework.web.bind.annotation.ExceptionHandler ;
import org.springframework.web.bind.annotation.RequestMapping ;
import org.springframework.web.context.request.WebRequest ;
import org.springframework.web.multipart.support.MissingServletRequestPartException ;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException ;
/ * *
* A convenient base for classes with { @link ExceptionHandler } methods providing
* infrastructure to handle standard Spring MVC exceptions . The functionality is
* equivalent to that of the { @link org . springframework . web . servlet . mvc . support . DefaultHandlerExceptionResolver DefaultHandlerExceptionResolver }
* except it can be customized to write error content to the body of the response . If
* there is no need to write error content , use { @code DefaultHandlerExceptionResolver }
* instead .
* A convenient base class for { @link ControllerAdvice @ControllerAdvice } classes
* that wish to provide centralized exception handling across all
* { @code @RequestMapping } methods through { @code @ExceptionHandler } methods .
*
* < p > It is expected the sub - classes will be annotated with
* { @link ControllerAdvice @ControllerAdvice } and that
* { @link ExceptionHandlerExceptionResolver } is configured to ensure this class
* applies to exceptions from any { @link RequestMapping @RequestMapping } method .
* < p > This base class provides an { @code @ExceptionHandler } for handling standard
* Spring MVC exceptions that returns a { @code ResponseEntity } to be written with
* { @link HttpMessageConverter message converters } . This is in contrast to
* { @link org . springframework . web . servlet . mvc . support . DefaultHandlerExceptionResolver
* DefaultHandlerExceptionResolver } which returns a { @code ModelAndView } instead .
*
* < p > If there is no need to write error content to the response body , or if using
* view resolution , e . g . { @code ContentNegotiatingViewResolver } , then use
* { @code DefaultHandlerExceptionResolver } instead .
*
* < p > Note that in order for an { @code @ControllerAdvice } sub - class to be
* detected , { @link ExceptionHandlerExceptionResolver } must be configured .
*
* @author Rossen Stoyanchev
* @since 3 . 2
*
* @see org . springframework . web . servlet . mvc . support . DefaultHandlerExceptionResolver
* /
public abstract class ExceptionHandlerSupport {
public abstract class ResponseEntity ExceptionHandler {
protected final Log logger = LogFactory . getLog ( getClass ( ) ) ;
@ -104,294 +108,290 @@ public abstract class ExceptionHandlerSupport {
@@ -104,294 +108,290 @@ public abstract class ExceptionHandlerSupport {
HttpHeaders headers = new HttpHeaders ( ) ;
HttpStatus status ;
Object body ;
if ( ex instanceof NoSuchRequestHandlingMethodException ) {
status = HttpStatus . NOT_FOUND ;
body = handleNoSuchRequestHandlingMethod ( ( NoSuchRequestHandlingMethodException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . NOT_FOUND ;
return handleNoSuchRequestHandlingMethod ( ( NoSuchRequestHandlingMethodException ) ex , headers , status , request ) ;
}
else if ( ex instanceof HttpRequestMethodNotSupportedException ) {
status = HttpStatus . METHOD_NOT_ALLOWED ;
body = handleHttpRequestMethodNotSupported ( ( HttpRequestMethodNotSupportedException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . METHOD_NOT_ALLOWED ;
return handleHttpRequestMethodNotSupported ( ( HttpRequestMethodNotSupportedException ) ex , headers , status , request ) ;
}
else if ( ex instanceof HttpMediaTypeNotSupportedException ) {
status = HttpStatus . UNSUPPORTED_MEDIA_TYPE ;
body = handleHttpMediaTypeNotSupported ( ( HttpMediaTypeNotSupportedException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . UNSUPPORTED_MEDIA_TYPE ;
return handleHttpMediaTypeNotSupported ( ( HttpMediaTypeNotSupportedException ) ex , headers , status , request ) ;
}
else if ( ex instanceof HttpMediaTypeNotAcceptableException ) {
status = HttpStatus . NOT_ACCEPTABLE ;
body = handleHttpMediaTypeNotAcceptable ( ( HttpMediaTypeNotAcceptableException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . NOT_ACCEPTABLE ;
return handleHttpMediaTypeNotAcceptable ( ( HttpMediaTypeNotAcceptableException ) ex , headers , status , request ) ;
}
else if ( ex instanceof MissingServletRequestParameterException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleMissingServletRequestParameter ( ( MissingServletRequestParameterException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleMissingServletRequestParameter ( ( MissingServletRequestParameterException ) ex , headers , status , request ) ;
}
else if ( ex instanceof ServletRequestBindingException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleServletRequestBindingException ( ( ServletRequestBindingException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleServletRequestBindingException ( ( ServletRequestBindingException ) ex , headers , status , request ) ;
}
else if ( ex instanceof ConversionNotSupportedException ) {
status = HttpStatus . INTERNAL_SERVER_ERROR ;
body = handleConversionNotSupported ( ( ConversionNotSupportedException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . INTERNAL_SERVER_ERROR ;
return handleConversionNotSupported ( ( ConversionNotSupportedException ) ex , headers , status , request ) ;
}
else if ( ex instanceof TypeMismatchException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleTypeMismatch ( ( TypeMismatchException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleTypeMismatch ( ( TypeMismatchException ) ex , headers , status , request ) ;
}
else if ( ex instanceof HttpMessageNotReadableException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleHttpMessageNotReadable ( ( HttpMessageNotReadableException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleHttpMessageNotReadable ( ( HttpMessageNotReadableException ) ex , headers , status , request ) ;
}
else if ( ex instanceof HttpMessageNotWritableException ) {
status = HttpStatus . INTERNAL_SERVER_ERROR ;
body = handleHttpMessageNotWritable ( ( HttpMessageNotWritableException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . INTERNAL_SERVER_ERROR ;
return handleHttpMessageNotWritable ( ( HttpMessageNotWritableException ) ex , headers , status , request ) ;
}
else if ( ex instanceof MethodArgumentNotValidException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleMethodArgumentNotValid ( ( MethodArgumentNotValidException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleMethodArgumentNotValid ( ( MethodArgumentNotValidException ) ex , headers , status , request ) ;
}
else if ( ex instanceof MissingServletRequestPartException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleMissingServletRequestPart ( ( MissingServletRequestPartException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleMissingServletRequestPart ( ( MissingServletRequestPartException ) ex , headers , status , request ) ;
}
else if ( ex instanceof BindException ) {
status = HttpStatus . BAD_REQUEST ;
body = handleBindException ( ( BindException ) ex , headers , status , request ) ;
HttpStatus status = HttpStatus . BAD_REQUEST ;
return handleBindException ( ( BindException ) ex , headers , status , request ) ;
}
else {
logger . warn ( "Unknown exception type: " + ex . getClass ( ) . getName ( ) ) ;
status = HttpStatus . INTERNAL_SERVER_ERROR ;
body = handleExceptionInternal ( ex , headers , status , request ) ;
HttpStatus status = HttpStatus . INTERNAL_SERVER_ERROR ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
return new ResponseEntity < Object > ( body , headers , status ) ;
}
/ * *
* A single place to customize the response body of all Exception types .
* This method returns { @code null } by default .
* @param ex the exception
* @param body the body to use for the response
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* /
protected Object handleExceptionInternal ( Exception ex , HttpHeaders headers , HttpStatus status , WebRequest request ) {
return null ;
protected ResponseEntity < Object > handleExceptionInternal ( Exception ex , Object body ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return new ResponseEntity < Object > ( body , headers , status ) ;
}
/ * *
* Customize the response for NoSuchRequestHandlingMethodException .
* This method logs a warning and delegates to
* { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleNoSuchRequestHandlingMethod ( NoSuchRequestHandlingMethodException ex ,
protected ResponseEntity < Object > handleNoSuchRequestHandlingMethod ( NoSuchRequestHandlingMethodException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
pageNotFoundLogger . warn ( ex . getMessage ( ) ) ;
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for HttpRequestMethodNotSupportedException .
* This method logs a warning , sets the "Allow" header , and delegates to
* { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleHttpRequestMethodNotSupported ( HttpRequestMethodNotSupportedException ex ,
protected ResponseEntity < Object > handleHttpRequestMethodNotSupported ( HttpRequestMethodNotSupportedException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
pageNotFoundLogger . warn ( ex . getMessage ( ) ) ;
Set < HttpMethod > mediaTypes = new HashSet < HttpMethod > ( ) ;
for ( String value : ex . getSupportedMethods ( ) ) {
mediaTypes . add ( HttpMethod . valueOf ( value ) ) ;
}
if ( ! mediaTypes . isEmpty ( ) ) {
headers . setAllow ( mediaTypes ) ;
Set < HttpMethod > supportedMethods = ex . getSupportedHttpMethods ( ) ;
if ( ! supportedMethods . isEmpty ( ) ) {
headers . setAllow ( supportedMethods ) ;
}
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for HttpMediaTypeNotSupportedException .
* This method sets the "Accept" header and delegates to
* { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleHttpMediaTypeNotSupported ( HttpMediaTypeNotSupportedException ex ,
protected ResponseEntity < Object > handleHttpMediaTypeNotSupported ( HttpMediaTypeNotSupportedException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
List < MediaType > mediaTypes = ex . getSupportedMediaTypes ( ) ;
if ( ! CollectionUtils . isEmpty ( mediaTypes ) ) {
headers . setAccept ( mediaTypes ) ;
}
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for HttpMediaTypeNotAcceptableException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleHttpMediaTypeNotAcceptable ( HttpMediaTypeNotAcceptableException ex ,
protected ResponseEntity < Object > handleHttpMediaTypeNotAcceptable ( HttpMediaTypeNotAcceptableException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for MissingServletRequestParameterException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleMissingServletRequestParameter ( MissingServletRequestParameterException ex ,
protected ResponseEntity < Object > handleMissingServletRequestParameter ( MissingServletRequestParameterException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for ServletRequestBindingException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleServletRequestBindingException ( ServletRequestBindingException ex ,
protected ResponseEntity < Object > handleServletRequestBindingException ( ServletRequestBindingException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for ConversionNotSupportedException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleConversionNotSupported ( ConversionNotSupportedException ex ,
protected ResponseEntity < Object > handleConversionNotSupported ( ConversionNotSupportedException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for TypeMismatchException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleTypeMismatch ( TypeMismatchException ex , HttpHeaders headers ,
protected ResponseEntity < Object > handleTypeMismatch ( TypeMismatchException ex , HttpHeaders headers ,
HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for HttpMessageNotReadableException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleHttpMessageNotReadable ( HttpMessageNotReadableException ex ,
protected ResponseEntity < Object > handleHttpMessageNotReadable ( HttpMessageNotReadableException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for HttpMessageNotWritableException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleHttpMessageNotWritable ( HttpMessageNotWritableException ex ,
protected ResponseEntity < Object > handleHttpMessageNotWritable ( HttpMessageNotWritableException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for MethodArgumentNotValidException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleMethodArgumentNotValid ( MethodArgumentNotValidException ex ,
protected ResponseEntity < Object > handleMethodArgumentNotValid ( MethodArgumentNotValidException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for MissingServletRequestPartException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleMissingServletRequestPart ( MissingServletRequestPartException ex ,
protected ResponseEntity < Object > handleMissingServletRequestPart ( MissingServletRequestPartException ex ,
HttpHeaders headers , HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
/ * *
* Customize the response for BindException .
* This method delegates to { @link # handleExceptionInternal ( Exception , HttpHeaders , HttpStatus , WebRequest ) } .
* This method delegates to { @link # handleExceptionInternal ( Exception , Object , HttpHeaders , HttpStatus , WebRequest ) } .
* @param ex the exception
* @param headers the headers to be written to the response
* @param status the selected response status
* @param request the current request
* @return an Object or { @code null }
* @return a { @code ResponseEntity } instance
* /
protected Object handleBindException ( BindException ex , HttpHeaders headers ,
protected ResponseEntity < Object > handleBindException ( BindException ex , HttpHeaders headers ,
HttpStatus status , WebRequest request ) {
return handleExceptionInternal ( ex , headers , status , request ) ;
return handleExceptionInternal ( ex , null , headers , status , request ) ;
}
}