diff --git a/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java b/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java index 051ebd430c0..34134c16c53 100644 --- a/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java +++ b/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java @@ -17,8 +17,13 @@ package org.springframework.web; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + import javax.servlet.ServletException; +import org.springframework.http.HttpMethod; + /** * Exception thrown when a request handler does not support a * specific request method. @@ -95,4 +100,15 @@ public class HttpRequestMethodNotSupportedException extends ServletException { return this.supportedMethods; } + /** + * Return the actually supported HTTP methods, if known, as {@link HttpMethod} instances. + */ + public Set getSupportedHttpMethods() { + Set supportedMethods = new HashSet(); + for (String value : this.supportedMethods) { + supportedMethods.add(HttpMethod.valueOf(value)); + } + return supportedMethods; + } + } diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java index 71aeac21104..6201383ffb0 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java @@ -32,7 +32,7 @@ import org.springframework.stereotype.Component; * *

It is typically used to define {@link ExceptionHandler @ExceptionHandler}, * {@link InitBinder @InitBinder}, and {@link ModelAttribute @ModelAttribute} - * methods that apply across controller class hierarchies. + * methods that apply to all {@link RequestMapping @RequestMapping} methods. * * @author Rossen Stoyanchev * @since 3.2 diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java similarity index 61% rename from spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerSupport.java rename to spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java index c1334f52e50..598340c5e35 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java @@ -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; 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; 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. * - *

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. + *

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. + * + *

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. + * + *

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 ResponseEntityExceptionHandler { protected final Log logger = LogFactory.getLog(getClass()); @@ -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(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 handleExceptionInternal(Exception ex, Object body, + HttpHeaders headers, HttpStatus status, WebRequest request) { + + return new ResponseEntity(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 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 handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { pageNotFoundLogger.warn(ex.getMessage()); - Set mediaTypes = new HashSet(); - for (String value : ex.getSupportedMethods()) { - mediaTypes.add(HttpMethod.valueOf(value)); - } - if (!mediaTypes.isEmpty()) { - headers.setAllow(mediaTypes); + Set 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 handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { List 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 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 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 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 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 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 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 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 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 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 handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { - return handleExceptionInternal(ex, headers, status, request); + return handleExceptionInternal(ex, null, headers, status, request); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java index bf0e69649f6..be2542d2b23 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java @@ -60,7 +60,7 @@ import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMeth * @author Rossen Stoyanchev * @since 3.0 * - * @see org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerSupport + * @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler * @see #handleNoSuchRequestHandlingMethod * @see #handleHttpRequestMethodNotSupported * @see #handleHttpMediaTypeNotSupported diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerSupportTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java similarity index 92% rename from spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerSupportTests.java rename to spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java index 04d28018cf4..e46c1872bb6 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerSupportTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java @@ -18,7 +18,6 @@ package org.springframework.web.servlet.mvc.method.annotation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.EnumSet; @@ -56,13 +55,13 @@ import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMeth import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; /** - * Test fixture for {@link ExceptionHandlerSupport}. + * Test fixture for {@link ResponseEntityExceptionHandler}. * * @author Rossen Stoyanchev */ -public class ExceptionHandlerSupportTests { +public class ResponseEntityExceptionHandlerTests { - private ExceptionHandlerSupport exceptionHandlerSupport; + private ResponseEntityExceptionHandler exceptionHandlerSupport; private DefaultHandlerExceptionResolver defaultExceptionResolver; @@ -86,7 +85,7 @@ public class ExceptionHandlerSupportTests { @Test public void supportsAllDefaultHandlerExceptionResolverExceptionTypes() throws Exception { - Method annotMethod = ExceptionHandlerSupport.class.getMethod("handleException", Exception.class, WebRequest.class); + Method annotMethod = ResponseEntityExceptionHandler.class.getMethod("handleException", Exception.class, WebRequest.class); ExceptionHandler annot = annotMethod.getAnnotation(ExceptionHandler.class); List> supportedTypes = Arrays.asList(annot.value()); @@ -217,14 +216,14 @@ public class ExceptionHandlerSupportTests { } @ControllerAdvice - private static class ApplicationExceptionHandler extends ExceptionHandlerSupport { + private static class ApplicationExceptionHandler extends ResponseEntityExceptionHandler { @Override - protected Object handleServletRequestBindingException(ServletRequestBindingException ex, + protected ResponseEntity handleServletRequestBindingException(ServletRequestBindingException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { headers.set("someHeader", "someHeaderValue"); - return "error content"; + return handleExceptionInternal(ex, "error content", headers, status, request); } diff --git a/src/reference/docbook/mvc.xml b/src/reference/docbook/mvc.xml index 40a89c7c9a8..76af127bd72 100644 --- a/src/reference/docbook/mvc.xml +++ b/src/reference/docbook/mvc.xml @@ -3843,15 +3843,23 @@ public class SimpleController { transparently by setting the status of the response. However, it stops short of writing any error content to the body of the response while your application may need to add developer-friendly content to every error - response for example when providing a REST API. + response for example when providing a REST API. You can prepare a + ModelAndView and + render error content through view resolution -- i.e. by configuring a + ContentNeogitatingViewResolver, + MappingJacksonJsonView, and so on. However, you + may prefer to use @ExceptionHandler + methods instead. - To achieve this extend ExceptionHandlerSupport, - a convenient base class with an @ExceptionHandler - method that handles standard Spring MVC exceptions just as the - DefaultHandlerExceptionResolver does but also - allowing you to prepare error content for the body of the response. - See the Javadoc of ExceptionHandlerSupport - for more details. + If you prefer to write error content via + @ExceptionHandler methods you can extend + ResponseEntityExceptionHandler instead. + This is a convenient base for @ControllerAdvice + classes providing an @ExceptionHandler + method to handle standard Spring MVC exceptions and return + ResponseEntity. That allows you to customize the response + and write error content with message converters. See the Javadoc of + ResponseEntityExceptionHandler for more details.
diff --git a/src/reference/docbook/new-in-3.2.xml b/src/reference/docbook/new-in-3.2.xml index ab5baf5dfa2..547b10bf1d0 100644 --- a/src/reference/docbook/new-in-3.2.xml +++ b/src/reference/docbook/new-in-3.2.xml @@ -66,7 +66,7 @@
- <interfacename>@ControllerAdvice</interfacename> annotation + New <interfacename>@ControllerAdvice</interfacename> annotation Classes annotated with @ControllerAdvice can contain @ExceptionHandler, @@ -81,13 +81,18 @@
- <classname>ExceptionHandlerSupport</classname> class + New <classname>ResponseEntityExceptionHandler</classname> class A convenient base class with an @ExceptionHandler - method that handles standard Spring MVC exceptions, just as the - DefaultHandlerExceptionResolver does, but also - allowing you to prepare error content for the body of the response. + method that handles standard Spring MVC exceptions and returns a + ResponseEntity that allowing customizing and writing + the response with HTTP message converters. This servers as an alternative + to the DefaultHandlerExceptionResolver, which does + the same but returns a ModelAndView instead. + + See the revised + including information on customizing the default Servlet container error page.