diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.java index f245b41b4bf..231967867fb 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -48,7 +47,6 @@ import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.ui.context.ThemeSource; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; -import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.multipart.MultipartException; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartResolver; @@ -57,88 +55,65 @@ import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.WebUtils; /** - * Central dispatcher for HTTP request handlers/controllers, - * e.g. for web UI controllers or HTTP-based remote service exporters. - * Dispatches to registered handlers for processing a web request, - * providing convenient mapping and exception handling facilities. + * Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service + * exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception + * handling facilities. * - *
This servlet is very flexible: It can be used with just about any workflow, - * with the installation of the appropriate adapter classes. It offers the - * following functionality that distinguishes it from other request-driven + *
This servlet is very flexible: It can be used with just about any workflow, with the installation of the + * appropriate adapter classes. It offers the following functionality that distinguishes it from other request-driven * web MVC frameworks: * - *
NOTE: The @RequestMapping annotation will only be processed
- * if a corresponding HandlerMapping (for type level annotations)
- * and/or HandlerAdapter (for method level annotations)
- * is present in the dispatcher. This is the case by default.
- * However, if you are defining custom HandlerMappings or
- * HandlerAdapters, then you need to make sure that a
- * corresponding custom DefaultAnnotationHandlerMapping
- * and/or AnnotationMethodHandlerAdapter is defined as well
- * - provided that you intend to use @RequestMapping.
+ *
NOTE: The @RequestMapping annotation will only be processed if a corresponding
+ * HandlerMapping (for type level annotations) and/or HandlerAdapter (for method level
+ * annotations) is present in the dispatcher. This is the case by default. However, if you are defining custom
+ * HandlerMappings or HandlerAdapters, then you need to make sure that a corresponding custom
+ * DefaultAnnotationHandlerMapping and/or AnnotationMethodHandlerAdapter is defined as well -
+ * provided that you intend to use @RequestMapping.
*
- *
A web application can define any number of DispatcherServlets. - * Each servlet will operate in its own namespace, loading its own application - * context with mappings, handlers, etc. Only the root application context - * as loaded by {@link org.springframework.web.context.ContextLoaderListener}, - * if any, will be shared. + *
A web application can define any number of DispatcherServlets. Each servlet will operate in its own
+ * namespace, loading its own application context with mappings, handlers, etc. Only the root application context as
+ * loaded by {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -149,102 +124,92 @@ import org.springframework.web.util.WebUtils;
*/
public class DispatcherServlet extends FrameworkServlet {
- /**
- * Well-known name for the MultipartResolver object in the bean factory for this namespace.
- */
+ /** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
- /**
- * Well-known name for the LocaleResolver object in the bean factory for this namespace.
- */
+ /** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
- /**
- * Well-known name for the ThemeResolver object in the bean factory for this namespace.
- */
+ /** Well-known name for the ThemeResolver object in the bean factory for this namespace. */
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
/**
- * Well-known name for the HandlerMapping object in the bean factory for this namespace.
- * Only used when "detectAllHandlerMappings" is turned off.
+ * Well-known name for the HandlerMapping object in the bean factory for this namespace. Only used when
+ * "detectAllHandlerMappings" is turned off.
+ *
* @see #setDetectAllHandlerMappings
*/
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
/**
- * Well-known name for the HandlerAdapter object in the bean factory for this namespace.
- * Only used when "detectAllHandlerAdapters" is turned off.
+ * Well-known name for the HandlerAdapter object in the bean factory for this namespace. Only used when
+ * "detectAllHandlerAdapters" is turned off.
+ *
* @see #setDetectAllHandlerAdapters
*/
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
/**
- * Well-known name for the HandlerExceptionResolver object in the bean factory for this
- * namespace. Only used when "detectAllHandlerExceptionResolvers" is turned off.
+ * Well-known name for the HandlerExceptionResolver object in the bean factory for this namespace. Only used when
+ * "detectAllHandlerExceptionResolvers" is turned off.
+ *
* @see #setDetectAllHandlerExceptionResolvers
*/
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
- /**
- * Well-known name for the RequestToViewNameTranslator object in the bean factory for
- * this namespace.
- */
+ /** Well-known name for the RequestToViewNameTranslator object in the bean factory for this namespace. */
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
/**
- * Well-known name for the ViewResolver object in the bean factory for this namespace.
- * Only used when "detectAllViewResolvers" is turned off.
+ * Well-known name for the ViewResolver object in the bean factory for this namespace. Only used when
+ * "detectAllViewResolvers" is turned off.
+ *
* @see #setDetectAllViewResolvers
*/
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
- /**
- * Request attribute to hold the currently chosen HandlerExecutionChain.
- * Only used for internal optimizations.
- */
+ /** Request attribute to hold the currently chosen HandlerExecutionChain. Only used for internal optimizations. */
public static final String HANDLER_EXECUTION_CHAIN_ATTRIBUTE = DispatcherServlet.class.getName() + ".HANDLER";
/**
- * Request attribute to hold the current web application context.
- * Otherwise only the global web app context is obtainable by tags etc.
+ * Request attribute to hold the current web application context. Otherwise only the global web app context is
+ * obtainable by tags etc.
+ *
* @see org.springframework.web.servlet.support.RequestContextUtils#getWebApplicationContext
*/
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
/**
* Request attribute to hold the current LocaleResolver, retrievable by views.
+ *
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocaleResolver
*/
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
/**
* Request attribute to hold the current ThemeResolver, retrievable by views.
+ *
* @see org.springframework.web.servlet.support.RequestContextUtils#getThemeResolver
*/
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
/**
* Request attribute to hold the current ThemeSource, retrievable by views.
+ *
* @see org.springframework.web.servlet.support.RequestContextUtils#getThemeSource
*/
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
-
- /**
- * Log category to use when no mapped handler is found for a request.
- */
+ /** Log category to use when no mapped handler is found for a request. */
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
/**
- * Name of the class path resource (relative to the DispatcherServlet class)
- * that defines DispatcherServlet's default strategy names.
+ * Name of the class path resource (relative to the DispatcherServlet class) that defines DispatcherServlet's default
+ * strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
-
- /**
- * Additional logger to use when no mapped handler is found for a request.
- */
+ /** Additional logger to use when no mapped handler is found for a request. */
protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
private static final Properties defaultStrategies;
@@ -262,7 +227,6 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
-
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;
@@ -278,7 +242,6 @@ public class DispatcherServlet extends FrameworkServlet {
/** Perform cleanup of request attributes after include request? */
private boolean cleanupAfterInclude = true;
-
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
@@ -303,80 +266,65 @@ public class DispatcherServlet extends FrameworkServlet {
/** List of ViewResolvers used by this servlet */
private List Default is "true". Turn this off if you want this servlet to use a
- * single HandlerMapping, despite multiple HandlerMapping beans being
- * defined in the context.
+ * Set whether to detect all HandlerMapping beans in this servlet's context. Else, just a single bean with name
+ * "handlerMapping" will be expected. Default is "true". Turn this off if you want this servlet to use a single
+ * HandlerMapping, despite multiple HandlerMapping beans being defined in the context.
*/
public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
this.detectAllHandlerMappings = detectAllHandlerMappings;
}
/**
- * Set whether to detect all HandlerAdapter beans in this servlet's context.
- * Else, just a single bean with name "handlerAdapter" will be expected.
- * Default is "true". Turn this off if you want this servlet to use a
- * single HandlerAdapter, despite multiple HandlerAdapter beans being
- * defined in the context.
+ * Set whether to detect all HandlerAdapter beans in this servlet's context. Else, just a single bean with name
+ * "handlerAdapter" will be expected. Default is "true". Turn this off if you want this servlet to use a single
+ * HandlerAdapter, despite multiple HandlerAdapter beans being defined in the context.
*/
public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
this.detectAllHandlerAdapters = detectAllHandlerAdapters;
}
/**
- * Set whether to detect all HandlerExceptionResolver beans in this servlet's context.
- * Else, just a single bean with name "handlerExceptionResolver" will be expected.
- * Default is "true". Turn this off if you want this servlet to use a
- * single HandlerExceptionResolver, despite multiple HandlerExceptionResolver
- * beans being defined in the context.
+ * Set whether to detect all HandlerExceptionResolver beans in this servlet's context. Else, just a single bean with
+ * name "handlerExceptionResolver" will be expected. Default is "true". Turn this off if you want this servlet to
+ * use a single HandlerExceptionResolver, despite multiple HandlerExceptionResolver beans being defined in the
+ * context.
*/
public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
this.detectAllHandlerExceptionResolvers = detectAllHandlerExceptionResolvers;
}
/**
- * Set whether to detect all ViewResolver beans in this servlet's context.
- * Else, just a single bean with name "viewResolver" will be expected.
- * Default is "true". Turn this off if you want this servlet to use a
- * single ViewResolver, despite multiple ViewResolver beans being
- * defined in the context.
+ * Set whether to detect all ViewResolver beans in this servlet's context. Else, just a single bean with name
+ * "viewResolver" will be expected. Default is "true". Turn this off if you want this servlet to use a single
+ * ViewResolver, despite multiple ViewResolver beans being defined in the context.
*/
public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
this.detectAllViewResolvers = detectAllViewResolvers;
}
/**
- * Set whether to perform cleanup of request attributes after an include request,
- * that is, whether to reset the original state of all request attributes after
- * the DispatcherServlet has processed within an include request. Else, just the
- * DispatcherServlet's own request attributes will be reset, but not model
- * attributes for JSPs or special attributes set by views (for example, JSTL's).
- * Default is "true", which is strongly recommended. Views should not rely on
- * request attributes having been set by (dynamic) includes. This allows JSP views
- * rendered by an included controller to use any model attributes, even with the
- * same names as in the main JSP, without causing side effects. Only turn this
- * off for special needs, for example to deliberately allow main JSPs to access
- * attributes from JSP views rendered by an included controller.
+ * Set whether to perform cleanup of request attributes after an include request, that is, whether to reset the
+ * original state of all request attributes after the DispatcherServlet has processed within an include request. Else,
+ * just the DispatcherServlet's own request attributes will be reset, but not model attributes for JSPs or special
+ * attributes set by views (for example, JSTL's). Default is "true", which is strongly recommended. Views should not
+ * rely on request attributes having been set by (dynamic) includes. This allows JSP views rendered by an included
+ * controller to use any model attributes, even with the same names as in the main JSP, without causing side effects.
+ * Only turn this off for special needs, for example to deliberately allow main JSPs to access attributes from JSP
+ * views rendered by an included controller.
*/
public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
this.cleanupAfterInclude = cleanupAfterInclude;
}
-
- /**
- * This implementation calls {@link #initStrategies}.
- */
+ /** This implementation calls {@link #initStrategies}. */
@Override
protected void onRefresh(ApplicationContext context) throws BeansException {
initStrategies(context);
}
/**
- * Initialize the strategy objects that this servlet uses.
- * May be overridden in subclasses in order to initialize
+ * Initialize the strategy objects that this servlet uses. May be overridden in subclasses in order to initialize
* further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
@@ -391,8 +339,7 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Initialize the MultipartResolver used by this class.
- * If no bean is defined with the given name in the BeanFactory
+ * Initialize the MultipartResolver used by this class. If no bean is defined with the given name in the BeanFactory
* for this namespace, no multipart handling is provided.
*/
private void initMultipartResolver(ApplicationContext context) {
@@ -406,15 +353,14 @@ public class DispatcherServlet extends FrameworkServlet {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
- logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
+ logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
/**
- * Initialize the LocaleResolver used by this class.
- * If no bean is defined with the given name in the BeanFactory
+ * Initialize the LocaleResolver used by this class. If no bean is defined with the given name in the BeanFactory
* for this namespace, we default to AcceptHeaderLocaleResolver.
*/
private void initLocaleResolver(ApplicationContext context) {
@@ -435,9 +381,8 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Initialize the ThemeResolver used by this class.
- * If no bean is defined with the given name in the BeanFactory
- * for this namespace, we default to a FixedThemeResolver.
+ * Initialize the ThemeResolver used by this class. If no bean is defined with the given name in the BeanFactory for
+ * this namespace, we default to a FixedThemeResolver.
*/
private void initThemeResolver(ApplicationContext context) {
try {
@@ -450,24 +395,24 @@ public class DispatcherServlet extends FrameworkServlet {
// We need to use the default.
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isDebugEnabled()) {
- logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
- "': using default [" + this.themeResolver + "]");
+ logger.debug(
+ "Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME + "': using default [" +
+ this.themeResolver + "]");
}
}
}
/**
- * Initialize the HandlerMappings used by this class.
- * If no HandlerMapping beans are defined in the BeanFactory
- * for this namespace, we default to BeanNameUrlHandlerMapping.
+ * Initialize the HandlerMappings used by this class. If no HandlerMapping beans are defined in the BeanFactory for
+ * this namespace, we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
- Map If no HandlerAdapter beans are defined in the BeanFactory
- * for this namespace, we default to SimpleControllerHandlerAdapter.
+ * Initialize the HandlerAdapters used by this class. If no HandlerAdapter beans are defined in the BeanFactory for
+ * this namespace, we default to SimpleControllerHandlerAdapter.
*/
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
- Map If no bean is defined with the given name in the BeanFactory
- * for this namespace, we default to no exception resolver.
+ * Initialize the HandlerExceptionResolver used by this class. If no bean is defined with the given name in the
+ * BeanFactory for this namespace, we default to no exception resolver.
*/
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
- Map If no ViewResolver beans are defined in the BeanFactory
- * for this namespace, we default to InternalResourceViewResolver.
+ * Initialize the ViewResolvers used by this class. If no ViewResolver beans are defined in the BeanFactory for this
+ * namespace, we default to InternalResourceViewResolver.
*/
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
- Map Default is to return the WebApplicationContext as ThemeSource,
- * provided that it implements the ThemeSource interface.
+ * Return this servlet's ThemeSource, if any; else return Default is to return the
+ * WebApplicationContext as ThemeSource, provided that it implements the ThemeSource interface.
+ *
* @return the ThemeSource, if any
* @see #getWebApplicationContext()
*/
@@ -650,18 +592,18 @@ public class DispatcherServlet extends FrameworkServlet {
/**
* Obtain this servlet's MultipartResolver, if any.
- * @return the MultipartResolver used by this servlet, or The default implementation delegates to {@link #getDefaultStrategies},
- * expecting a single object in the list.
+ * Return the default strategy object for the given strategy interface. The default implementation delegates to
+ * {@link #getDefaultStrategies}, expecting a single object in the list.
+ *
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the corresponding strategy object
@@ -677,10 +619,10 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Create a List of default strategy objects for the given strategy interface.
- * The default implementation uses the "DispatcherServlet.properties" file
- * (in the same package as the DispatcherServlet class) to determine the class names.
- * It instantiates the strategy objects through the context's BeanFactory.
+ * Create a List of default strategy objects for the given strategy interface. The default implementation uses the
+ * "DispatcherServlet.properties" file (in the same package as the DispatcherServlet class) to determine the class
+ * names. It instantiates the strategy objects through the context's BeanFactory.
+ *
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the List of corresponding strategy objects
@@ -717,13 +659,12 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Create a default strategy.
- * The default implementation uses
- * {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}.
+ * Create a default strategy. The default implementation uses {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}.
+ *
* @param context the current WebApplicationContext
* @param clazz the strategy implementation class to instantiate
- * @throws BeansException if initialization failed
* @return the fully configured strategy instance
+ * @throws BeansException if initialization failed
* @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory()
* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean
*/
@@ -731,17 +672,16 @@ public class DispatcherServlet extends FrameworkServlet {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
-
/**
- * Exposes the DispatcherServlet-specific request attributes and
- * delegates to {@link #doDispatch} for the actual dispatching.
+ * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} for the actual
+ * dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = new UrlPathHelper().getRequestUri(request);
- logger.debug("DispatcherServlet with name '" + getServletName() +
- "' processing " + request.getMethod() + " request for [" + requestUri + "]");
+ logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
+ " request for [" + requestUri + "]");
}
// Keep a snapshot of the request attributes in case of an include,
@@ -777,12 +717,11 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Process the actual dispatching to the handler.
- * The handler will be obtained by applying the servlet's HandlerMappings in order.
- * The HandlerAdapter will be obtained by querying the servlet's installed
- * HandlerAdapters to find the first that supports the handler class.
- * All HTTP methods are handled by this method. It's up to HandlerAdapters or
- * handlers themselves to decide which methods are acceptable.
+ * Process the actual dispatching to the handler. The handler will be obtained by applying the servlet's
+ * HandlerMappings in order. The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters to
+ * find the first that supports the handler class. All HTTP methods are handled by this method. It's up to
+ * HandlerAdapters or handlers themselves to decide which methods are acceptable.
+ *
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
@@ -855,8 +794,8 @@ public class DispatcherServlet extends FrameworkServlet {
}
else {
if (logger.isDebugEnabled()) {
- logger.debug("Null ModelAndView returned to DispatcherServlet with name '" +
- getServletName() + "': assuming HandlerAdapter completed request handling");
+ logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
+ "': assuming HandlerAdapter completed request handling");
}
}
@@ -885,15 +824,16 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Override HttpServlet's The default implementation uses the dispatcher's LocaleResolver
- * to obtain the current locale, which might change during a request.
+ * Build a LocaleContext for the given request, exposing the request's primary locale as current locale. The default
+ * implementation uses the dispatcher's LocaleResolver to obtain the current locale, which might change during a
+ * request.
+ *
* @param request current HTTP request
* @return the corresponding LocaleContext
*/
@@ -933,6 +872,7 @@ public class DispatcherServlet extends FrameworkServlet {
public Locale getLocale() {
return localeResolver.resolveLocale(request);
}
+
@Override
public String toString() {
return getLocale().toString();
@@ -941,8 +881,9 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Convert the request into a multipart request, and make multipart resolver available.
- * If no multipart resolver is set, simply use the existing request.
+ * Convert the request into a multipart request, and make multipart resolver available. If no multipart resolver is
+ * set, simply use the existing request.
+ *
* @param request current HTTP request
* @return the processed request (multipart wrapper if necessary)
* @see MultipartResolver#resolveMultipart
@@ -963,6 +904,7 @@ public class DispatcherServlet extends FrameworkServlet {
/**
* Clean up any resources used by the given multipart request (if any).
+ *
* @param request current HTTP request
* @see MultipartResolver#cleanupMultipart
*/
@@ -973,15 +915,14 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Return the HandlerExecutionChain for this request.
- * Try all handler mappings in order.
+ * Return the HandlerExecutionChain for this request. Try all handler mappings in order.
+ *
* @param request current HTTP request
* @param cache whether to cache the HandlerExecutionChain in a request attribute
* @return the HandlerExceutionChain, or Default implementations asks all ViewResolvers of this dispatcher.
- * Can be overridden for custom resolution strategies, potentially based
- * on specific model attributes or request parameters.
+ * Resolve the given view name into a View object (to be rendered). Default implementations asks all ViewResolvers
+ * of this dispatcher. Can be overridden for custom resolution strategies, potentially based on specific model
+ * attributes or request parameters.
+ *
* @param viewName the name of the view to resolve
* @param model the model to be passed to the view
* @param locale the current locale
* @param request current HTTP servlet request
* @return the View object, or Provides a set of mapped handlers that
+ * the resolver should map to, and the {@link Ordered} implementation.
+ *
+ * @author Arjen Poutsma
+ * @since 3.0
+ */
+public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private int order = Ordered.LOWEST_PRECEDENCE;
+
+ private Set mappedHandlers;
+
+ private Class[] mappedHandlerClasses;
+
+ private Log warnLogger;
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ public int getOrder() {
+ return this.order;
+ }
+
+ /**
+ * Specify the set of handlers that this exception resolver should apply to. The exception mappings and the default
+ * error view will only apply to the specified handlers. If no handlers and handler classes are set, the exception
+ * mappings and the default error view will apply to all handlers. This means that a specified default error view will
+ * be used as fallback for all exceptions; any further HandlerExceptionResolvers in the chain will be ignored in this
+ * case.
+ */
+ public void setMappedHandlers(Set mappedHandlers) {
+ this.mappedHandlers = mappedHandlers;
+ }
+
+ /**
+ * Specify the set of classes that this exception resolver should apply to. The exception mappings and the default
+ * error view will only apply to handlers of the specified type; the specified types may be interfaces and superclasses
+ * of handlers as well. If no handlers and handler classes are set, the exception mappings and the default error
+ * view will apply to all handlers. This means that a specified default error view will be used as fallback for all
+ * exceptions; any further HandlerExceptionResolvers in the chain will be ignored in this case.
+ */
+ public void setMappedHandlerClasses(Class[] mappedHandlerClasses) {
+ this.mappedHandlerClasses = mappedHandlerClasses;
+ }
+
+ /**
+ * Set the log category for warn logging. The name will be passed to the underlying logger implementation through
+ * Commons Logging, getting interpreted as log category according to the logger's configuration. Default is no warn
+ * logging. Specify this setting to activate warn logging into a specific category. Alternatively, override the {@link
+ * #logException} method for custom logging.
+ *
+ * @see org.apache.commons.logging.LogFactory#getLog(String)
+ * @see org.apache.log4j.Logger#getLogger(String)
+ * @see java.util.logging.Logger#getLogger(String)
+ */
+ public void setWarnLogCategory(String loggerName) {
+ this.warnLogger = LogFactory.getLog(loggerName);
+ }
+
+ /**
+ * Checks whether this resolver is supposed to apply (i.e. the handler matches in case of "mappedHandlers" having been
+ * specified), then delegates to the {@link #doResolveException} template method.
+ */
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler,
+ Exception ex) {
+
+ if (shouldApplyTo(request, handler)) {
+ // Log exception, both at debug log level and at warn level, if desired.
+ if (logger.isDebugEnabled()) {
+ logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
+ }
+ logException(ex, request);
+ return doResolveException(request, response, handler, ex);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Check whether this resolver is supposed to apply to the given handler. The default implementation checks against
+ * the specified mapped handlers and handler classes, if any.
+ *
+ * @param request current HTTP request
+ * @param handler the executed handler, or Calls {@link #buildLogMessage} in order to determine the
+ * concrete message to log. Always passes the full exception to the logger.
+ *
+ * @param ex the exception that got thrown during handler execution
+ * @param request current HTTP request (useful for obtaining metadata)
+ * @see #setWarnLogCategory
+ * @see #buildLogMessage
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ protected void logException(Exception ex, HttpServletRequest request) {
+ if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
+ this.warnLogger.warn(buildLogMessage(ex, request), ex);
+ }
+ }
+
+ /**
+ * Build a log message for the given exception, occured during processing the given request.
+ *
+ * @param ex the exception that got thrown during handler execution
+ * @param request current HTTP request (useful for obtaining metadata)
+ * @return the log message to use
+ */
+ protected String buildLogMessage(Exception ex, HttpServletRequest request) {
+ return "Handler execution resulted in exception";
+ }
+
+ /**
+ * Actually resolve the given exception that got thrown during on handler execution, returning a ModelAndView that
+ * represents a specific error page if appropriate. May be overridden in subclasses, in order to apply specific
+ * exception checks. Note that this template method will be invoked after checking whether this resolved applies
+ * ("mappedHandlers" etc), so an implementation may simply proceed with its actual exception handling.
+ *
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or Default implementations typically
+ * set the response status.
+ *
+ * @author Arjen Poutsma
+ * @see #handleNoSuchRequestHandlingMethod
+ * @see #handleHttpRequestMethodNotSupported
+ * @see #handleHttpMediaTypeNotSupported
+ * @see #handleMissingServletRequestParameter
+ * @see #handleTypeMismatch
+ * @see #handleHttpMessageNotReadable
+ * @see #handleHttpMessageNotWritable
+ * @since 3.0
+ */
+public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
+
+ /**
+ * Log category to use when no mapped handler is found for a request.
+ *
+ * @see #pageNotFoundLogger
+ */
+ public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
+
+ /**
+ * Additional logger to use when no mapped handler is found for a request.
+ *
+ * @see #PAGE_NOT_FOUND_LOG_CATEGORY
+ */
+ protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
+
+ /** Sets the {@linkplain #setOrder(int) order} to {@link #LOWEST_PRECEDENCE}. */
+ public DefaultHandlerExceptionResolver() {
+ setOrder(Ordered.LOWEST_PRECEDENCE);
+ }
+
+ @Override
+ protected ModelAndView doResolveException(HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler,
+ Exception ex) {
+ try {
+ if (ex instanceof NoSuchRequestHandlingMethodException) {
+ return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, request, response,
+ handler);
+ }
+ else if (ex instanceof HttpRequestMethodNotSupportedException) {
+ return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
+ response, handler);
+ }
+ else if (ex instanceof HttpMediaTypeNotSupportedException) {
+ return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
+ handler);
+ }
+ else if (ex instanceof MissingServletRequestParameterException) {
+ return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request,
+ response, handler);
+ }
+ else if (ex instanceof TypeMismatchException) {
+ return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
+ }
+ else if (ex instanceof HttpMessageNotReadableException) {
+ return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
+ }
+ else if (ex instanceof HttpMessageNotWritableException) {
+ return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
+ }
+ }
+ catch (Exception handlerException) {
+ logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
+ }
+ return null;
+ }
+
+ /**
+ * Handle the case where no request handler method was found. The default implementation logs a warning, sends an
+ * HTTP 404 error, and returns an empty {@code ModelAndView}. Alternatively, a fallback view could be chosen, or the
+ * NoSuchRequestHandlingMethodException could be rethrown as-is.
+ *
+ * @param ex the NoSuchRequestHandlingMethodException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or The default
+ * implementation logs a warning, sends an HTTP 405 error, sets the "Allow" header, and returns an empty {@code
+ * ModelAndView}. Alternatively, a fallback view could be chosen, or the HttpRequestMethodNotSupportedException could
+ * be rethrown as-is.
+ *
+ * @param ex the HttpRequestMethodNotSupportedException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or The default implementation sends an HTTP 415 error, sets the "Allow"
+ * header, and returns an empty {@code ModelAndView}. Alternatively, a fallback view could be chosen, or the
+ * HttpMediaTypeNotSupportedException could be rethrown as-is.
+ *
+ * @param ex the HttpMediaTypeNotSupportedException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or The default implementation sends an HTTP 400 error, and
+ * returns an empty {@code ModelAndView}. Alternatively, a fallback view could be chosen, or the
+ * MissingServletRequestParameterException could be rethrown as-is.
+ *
+ * @param ex the MissingServletRequestParameterException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or The default
+ * implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}. Alternatively, a fallback view
+ * could be chosen, or the TypeMismatchException could be rethrown as-is.
+ *
+ * @param ex the TypeMismatchException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or The default implementation sends an HTTP 400 error, and returns an empty {@code
+ * ModelAndView}. Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotSupportedException could be
+ * rethrown as-is.
+ *
+ * @param ex the HttpMessageNotReadableException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or The default implementation sends an HTTP 500 error, and returns an empty {@code
+ * ModelAndView}. Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotSupportedException could be
+ * rethrown as-is.
+ *
+ * @param ex the HttpMessageNotWritableException to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the executed handler, or Error views are analogous to error page JSPs, but can be used with any
- * kind of exception including any checked one, with fine-granular mappings for
- * specific handlers.
+ * Error views are analogous to error page JSPs, but can be used with any kind of exception including any checked
+ * one, with fine-granular mappings for specific handlers.
*
* @author Juergen Hoeller
- * @since 22.11.2003
+ * @author Arjen Poutsma
* @see org.springframework.web.servlet.DispatcherServlet
+ * @since 22.11.2003
*/
-public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, Ordered {
+public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionResolver {
- /**
- * The default name of the exception attribute: "exception".
- */
+ /** The default name of the exception attribute: "exception". */
public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
-
- /** Logger available to subclasses */
- protected final Log logger = LogFactory.getLog(getClass());
-
- private int order = Integer.MAX_VALUE; // default: same as non-Ordered
-
- private Set mappedHandlers;
-
- private Class[] mappedHandlerClasses;
-
- private Log warnLogger;
-
private Properties exceptionMappings;
private String defaultErrorView;
@@ -71,74 +49,18 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
private String exceptionAttribute = DEFAULT_EXCEPTION_ATTRIBUTE;
-
- public void setOrder(int order) {
- this.order = order;
- }
-
- public int getOrder() {
- return this.order;
- }
-
/**
- * Specify the set of handlers that this exception resolver should apply to.
- * The exception mappings and the default error view will only apply
- * to the specified handlers.
- * If no handlers and handler classes are set, the exception mappings
- * and the default error view will apply to all handlers. This means that
- * a specified default error view will be used as fallback for all exceptions;
- * any further HandlerExceptionResolvers in the chain will be ignored in
- * this case.
- */
- public void setMappedHandlers(Set mappedHandlers) {
- this.mappedHandlers = mappedHandlers;
- }
-
- /**
- * Specify the set of classes that this exception resolver should apply to.
- * The exception mappings and the default error view will only apply
- * to handlers of the specified type; the specified types may be interfaces
- * and superclasses of handlers as well.
- * If no handlers and handler classes are set, the exception mappings
- * and the default error view will apply to all handlers. This means that
- * a specified default error view will be used as fallback for all exceptions;
- * any further HandlerExceptionResolvers in the chain will be ignored in
- * this case.
- */
- public void setMappedHandlerClasses(Class[] mappedHandlerClasses) {
- this.mappedHandlerClasses = mappedHandlerClasses;
- }
-
- /**
- * Set the log category for warn logging. The name will be passed to the
- * underlying logger implementation through Commons Logging, getting
- * interpreted as log category according to the logger's configuration.
- * Default is no warn logging. Specify this setting to activate
- * warn logging into a specific category. Alternatively, override
- * the {@link #logException} method for custom logging.
- * @see org.apache.commons.logging.LogFactory#getLog(String)
- * @see org.apache.log4j.Logger#getLogger(String)
- * @see java.util.logging.Logger#getLogger(String)
- */
- public void setWarnLogCategory(String loggerName) {
- this.warnLogger = LogFactory.getLog(loggerName);
- }
-
- /**
- * Set the mappings between exception class names and error view names.
- * The exception class name can be a substring, with no wildcard support
- * at present. A value of "ServletException" would match
- * NB: Consider carefully how specific the pattern is, and whether
- * to include package information (which isn't mandatory). For example,
- * "Exception" will match nearly anything, and will probably hide other rules.
- * "java.lang.Exception" would be correct if "Exception" was meant to define
- * a rule for all checked exceptions. With more unusual exception names such
- * as "BaseBusinessException" there's no need to use a FQN.
- * Follows the same matching algorithm as RuleBasedTransactionAttribute
- * and RollbackRuleAttribute.
- * @param mappings exception patterns (can also be fully qualified class names)
- * as keys, and error view names as values
+ * Set the mappings between exception class names and error view names. The exception class name can be a substring,
+ * with no wildcard support at present. A value of "ServletException" would match
+ * NB: Consider carefully how
+ * specific the pattern is, and whether to include package information (which isn't mandatory). For example,
+ * "Exception" will match nearly anything, and will probably hide other rules. "java.lang.Exception" would be correct
+ * if "Exception" was meant to define a rule for all checked exceptions. With more unusual exception names such as
+ * "BaseBusinessException" there's no need to use a FQN. Follows the same matching algorithm as
+ * RuleBasedTransactionAttribute and RollbackRuleAttribute.
+ *
+ * @param mappings exception patterns (can also be fully qualified class names) as keys, and error view names as
+ * values
* @see org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
* @see org.springframework.transaction.interceptor.RollbackRuleAttribute
*/
@@ -147,24 +69,20 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
/**
- * Set the name of the default error view.
- * This view will be returned if no specific mapping was found.
- * Default is none.
+ * Set the name of the default error view. This view will be returned if no specific mapping was found. Default is
+ * none.
*/
public void setDefaultErrorView(String defaultErrorView) {
this.defaultErrorView = defaultErrorView;
}
/**
- * Set the default HTTP status code that this exception resolver will apply
- * if it resolves an error view.
- * Note that this error code will only get applied in case of a top-level
- * request. It will not be set for an include request, since the HTTP status
- * cannot be modified from within an include.
- * If not specified, no status code will be applied, either leaving this to
- * the controller or view, or keeping the servlet engine's default of 200 (OK).
- * @param defaultStatusCode HTTP status code value, for example
- * 500 (SC_INTERNAL_SERVER_ERROR) or 404 (SC_NOT_FOUND)
+ * Set the default HTTP status code that this exception resolver will apply if it resolves an error view. Note that
+ * this error code will only get applied in case of a top-level request. It will not be set for an include request,
+ * since the HTTP status cannot be modified from within an include. If not specified, no status code will be
+ * applied, either leaving this to the controller or view, or keeping the servlet engine's default of 200 (OK).
+ *
+ * @param defaultStatusCode HTTP status code value, for example 500 (SC_INTERNAL_SERVER_ERROR) or 404 (SC_NOT_FOUND)
* @see javax.servlet.http.HttpServletResponse#SC_INTERNAL_SERVER_ERROR
* @see javax.servlet.http.HttpServletResponse#SC_NOT_FOUND
*/
@@ -173,84 +91,33 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
/**
- * Set the name of the model attribute as which the exception should
- * be exposed. Default is "exception".
- * This can be either set to a different attribute name or to
- * This can be
+ * either set to a different attribute name or to The default implementation checks against the specified mapped handlers
- * and handler classes, if any.
- * @param request current HTTP request
- * @param handler the executed handler, or May be overridden in subclasses, in order to apply specific exception checks.
- * Note that this template method will be invoked after checking whether
- * this resolved applies ("mappedHandlers" etc), so an implementation may simply
- * proceed with its actual exception handling.
+ * Actually resolve the given exception that got thrown during on handler execution, returning a ModelAndView that
+ * represents a specific error page if appropriate. May be overridden in subclasses, in order to apply specific
+ * exception checks. Note that this template method will be invoked after checking whether this resolved applies
+ * ("mappedHandlers" etc), so an implementation may simply proceed with its actual exception handling.
+ *
* @param request current HTTP request
* @param response current HTTP response
- * @param handler the executed handler, or Calls {@link #buildLogMessage} in order to determine the concrete message
- * to log. Always passes the full exception to the logger.
- * @param ex the exception that got thrown during handler execution
- * @param request current HTTP request (useful for obtaining metadata)
- * @see #setWarnLogCategory
- * @see #buildLogMessage
- * @see org.apache.commons.logging.Log#warn(Object, Throwable)
- */
- protected void logException(Exception ex, HttpServletRequest request) {
- if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
- this.warnLogger.warn(buildLogMessage(ex, request), ex);
- }
- }
-
- /**
- * Build a log message for the given exception, occured during processing
- * the given request.
- * @param ex the exception that got thrown during handler execution
- * @param request current HTTP request (useful for obtaining metadata)
- * @return the log message to use
- */
- protected String buildLogMessage(Exception ex, HttpServletRequest request) {
- return "Handler execution resulted in exception";
- }
-
-
- /**
- * Determine the view name for the given exception, searching the
- * {@link #setExceptionMappings "exceptionMappings"}, using the
- * {@link #setDefaultErrorView "defaultErrorView"} as fallback.
+ * Determine the view name for the given exception, searching the {@link #setExceptionMappings "exceptionMappings"},
+ * using the {@link #setDefaultErrorView "defaultErrorView"} as fallback.
+ *
* @param ex the exception that got thrown during handler execution
* @param request current HTTP request (useful for obtaining metadata)
* @return the resolved view name, or 0 means ex matches exactly. Returns -1 if there's no match.
- * Otherwise, returns depth. Lowest depth wins.
- * Follows the same algorithm as
- * {@link org.springframework.transaction.interceptor.RollbackRuleAttribute}.
+ * Return the depth to the superclass matching. 0 means ex matches exactly. Returns -1 if there's no match.
+ * Otherwise, returns depth. Lowest depth wins. Follows the same algorithm as {@link
+ * org.springframework.transaction.interceptor.RollbackRuleAttribute}.
*/
protected int getDepth(String exceptionMapping, Exception ex) {
return getDepth(exceptionMapping, ex.getClass(), 0);
@@ -373,17 +209,15 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
}
-
/**
- * Determine the HTTP status code to apply for the given error view.
- * The default implementation always returns the specified
- * {@link #setDefaultStatusCode "defaultStatusCode"}, as a common
- * status code for all error views. Override this in a custom subclass
- * to determine a specific status code for the given view.
+ * Determine the HTTP status code to apply for the given error view. The default implementation always returns the
+ * specified {@link #setDefaultStatusCode "defaultStatusCode"}, as a common status code for all error views. Override
+ * this in a custom subclass to determine a specific status code for the given view.
+ *
* @param request current HTTP request
* @param viewName the name of the error view
- * @return the HTTP status code to use, or The default implementation delegates to {@link #getModelAndView(String, Exception)}.
+ * Return a ModelAndView for the given request, view name and exception. The default implementation delegates to
+ * {@link #getModelAndView(String, Exception)}.
+ *
* @param viewName the name of the error view
* @param ex the exception that got thrown during handler execution
* @param request current HTTP request (useful for obtaining metadata)
@@ -424,9 +260,9 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
/**
- * Return a ModelAndView for the given view name and exception.
- * The default implementation adds the specified exception attribute.
- * Can be overridden in subclasses.
+ * Return a ModelAndView for the given view name and exception. The default implementation adds the specified
+ * exception attribute. Can be overridden in subclasses.
+ *
* @param viewName the name of the error view
* @param ex the exception that got thrown during handler execution
* @return the ModelAndView instance
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
index 3b419798e3e..4cc68680ce3 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
@@ -52,7 +52,6 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpInputMessage;
-import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
@@ -68,7 +67,6 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.validation.support.BindingAwareModelMap;
-import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.HttpSessionRequiredException;
import org.springframework.web.bind.MissingServletRequestParameterException;
@@ -101,38 +99,36 @@ import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.WebUtils;
/**
- * Implementation of the {@link org.springframework.web.servlet.HandlerAdapter}
- * interface that maps handler methods based on HTTP paths, HTTP methods and
- * request parameters expressed through the {@link RequestMapping} annotation.
+ * Implementation of the {@link org.springframework.web.servlet.HandlerAdapter} interface that maps handler methods
+ * based on HTTP paths, HTTP methods and request parameters expressed through the {@link RequestMapping} annotation.
*
- * Supports request parameter binding through the {@link RequestParam} annotation.
- * Also supports the {@link ModelAttribute} annotation for exposing model attribute
- * values to the view, as well as {@link InitBinder} for binder initialization methods
- * and {@link SessionAttributes} for automatic session management of specific attributes.
+ * Supports request parameter binding through the {@link RequestParam} annotation. Also supports the {@link
+ * ModelAttribute} annotation for exposing model attribute values to the view, as well as {@link InitBinder} for binder
+ * initialization methods and {@link SessionAttributes} for automatic session management of specific attributes.
*
- * This adapter can be customized through various bean properties.
- * A common use case is to apply shared binder initialization logic through
- * a custom {@link #setWebBindingInitializer WebBindingInitializer}.
+ * This adapter can be customized through various bean properties. A common use case is to apply shared binder
+ * initialization logic through a custom {@link #setWebBindingInitializer WebBindingInitializer}.
*
* @author Juergen Hoeller
* @author Arjen Poutsma
- * @since 2.5
* @see #setPathMatcher
* @see #setMethodNameResolver
* @see #setWebBindingInitializer
* @see #setSessionAttributeStore
+ * @since 2.5
*/
public class AnnotationMethodHandlerAdapter extends WebContentGenerator implements HandlerAdapter {
/**
* Log category to use when no mapped handler is found for a request.
+ *
* @see #pageNotFoundLogger
*/
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
-
/**
* Additional logger to use when no mapped handler is found for a request.
+ *
* @see #PAGE_NOT_FOUND_LOG_CATEGORY
*/
protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
@@ -167,12 +163,11 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
super(false);
}
-
/**
- * Set if URL lookup should always use the full path within the current servlet
- * context. Else, the path within the current servlet mapping is used if applicable
- * (that is, in the case of a ".../*" servlet mapping in web.xml).
+ * Set if URL lookup should always use the full path within the current servlet context. Else, the path within the
+ * current servlet mapping is used if applicable (that is, in the case of a ".../*" servlet mapping in web.xml).
* Default is "false".
+ *
* @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
@@ -180,10 +175,10 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Set if context path and request URI should be URL-decoded. Both are returned
- * undecoded by the Servlet API, in contrast to the servlet path.
- * Uses either the request encoding or the default encoding according
- * to the Servlet spec (ISO-8859-1).
+ * Set if context path and request URI should be URL-decoded. Both are returned undecoded by the Servlet API, in
+ * contrast to the servlet path. Uses either the request encoding or the default encoding according to the Servlet
+ * spec (ISO-8859-1).
+ *
* @see org.springframework.web.util.UrlPathHelper#setUrlDecode
*/
public void setUrlDecode(boolean urlDecode) {
@@ -191,10 +186,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Set the UrlPathHelper to use for resolution of lookup paths.
- * Use this to override the default UrlPathHelper with a custom subclass,
- * or to share common UrlPathHelper settings across multiple HandlerMappings
- * and HandlerAdapters.
+ * Set the UrlPathHelper to use for resolution of lookup paths. Use this to override the default UrlPathHelper with
+ * a custom subclass, or to share common UrlPathHelper settings across multiple HandlerMappings and HandlerAdapters.
*/
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
@@ -202,8 +195,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Set the PathMatcher implementation to use for matching URL paths
- * against registered URL patterns. Default is AntPathMatcher.
+ * Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. Default is
+ * AntPathMatcher.
+ *
* @see org.springframework.util.AntPathMatcher
*/
public void setPathMatcher(PathMatcher pathMatcher) {
@@ -212,9 +206,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Set the MethodNameResolver to use for resolving default handler methods
- * (carrying an empty Will only kick in when the handler method cannot be resolved uniquely
+ * Set the MethodNameResolver to use for resolving default handler methods (carrying an empty
+ * Will only kick in when the handler method cannot be resolved uniquely
* through the annotation metadata already.
*/
public void setMethodNameResolver(MethodNameResolver methodNameResolver) {
@@ -222,18 +215,16 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Specify a WebBindingInitializer which will apply pre-configured
- * configuration to every DataBinder that this controller uses.
+ * Specify a WebBindingInitializer which will apply pre-configured configuration to every DataBinder that this
+ * controller uses.
*/
public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
this.webBindingInitializer = webBindingInitializer;
}
/**
- * Specify the strategy to store session attributes with.
- * Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
- * storing session attributes in the HttpSession, using the same
- * attribute name as in the model.
+ * Specify the strategy to store session attributes with. Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
+ * storing session attributes in the HttpSession, using the same attribute name as in the model.
*/
public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
Assert.notNull(sessionAttributeStore, "SessionAttributeStore must not be null");
@@ -241,11 +232,11 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Cache content produced by In contrast to the "cacheSeconds" property which will apply to all general
- * handlers (but not to In contrast to the "cacheSeconds" property which will apply to all
+ * general handlers (but not to More specifically, the execution of each handler method will get
- * synchronized if this flag is "true". The best available session mutex
- * will be used for the synchronization; ideally, this will be a mutex
- * exposed by HttpSessionMutexListener.
- * The session mutex is guaranteed to be the same object during
- * the entire lifetime of the session, available under the key defined
- * by the In many cases, the HttpSession reference itself is a safe mutex
- * as well, since it will always be the same object reference for the
- * same active logical session. However, this is not guaranteed across
- * different servlet containers; the only 100% safe way is a session mutex.
+ * Set if controller execution should be synchronized on the session, to serialize parallel invocations from the same
+ * client. More specifically, the execution of each handler method will get synchronized if this flag is "true". The
+ * best available session mutex will be used for the synchronization; ideally, this will be a mutex exposed by
+ * HttpSessionMutexListener. The session mutex is guaranteed to be the same object during the entire lifetime of the
+ * session, available under the key defined by the In many cases, the HttpSession reference itself
+ * is a safe mutex as well, since it will always be the same object reference for the same active logical session.
+ * However, this is not guaranteed across different servlet containers; the only 100% safe way is a session mutex.
+ *
* @see org.springframework.web.util.HttpSessionMutexListener
* @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
*/
@@ -276,44 +262,38 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Set the ParameterNameDiscoverer to use for resolving method parameter
- * names if needed (e.g. for default attribute names).
- * Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
+ * Set the ParameterNameDiscoverer to use for resolving method parameter names if needed (e.g. for default attribute
+ * names). Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
*/
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
- * Set a custom ArgumentResolvers to use for special method parameter types.
- * Such a custom ArgumentResolver will kick in first, having a chance to
- * resolve an argument value before the standard argument handling kicks in.
+ * Set a custom ArgumentResolvers to use for special method parameter types. Such a custom ArgumentResolver will kick
+ * in first, having a chance to resolve an argument value before the standard argument handling kicks in.
*/
public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) {
- this.customArgumentResolvers = new WebArgumentResolver[] {argumentResolver};
+ this.customArgumentResolvers = new WebArgumentResolver[]{argumentResolver};
}
/**
- * Set one or more custom ArgumentResolvers to use for special method
- * parameter types. Any such custom ArgumentResolver will kick in first,
- * having a chance to resolve an argument value before the standard
- * argument handling kicks in.
+ * Set one or more custom ArgumentResolvers to use for special method parameter types. Any such custom ArgumentResolver
+ * will kick in first, having a chance to resolve an argument value before the standard argument handling kicks in.
*/
public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) {
this.customArgumentResolvers = argumentResolvers;
}
/**
- * Set the message body converters to use. These converters are used to convert
- * from and to HTTP requests and responses.
+ * Set the message body converters to use. These converters are used to convert from and to HTTP requests and
+ * responses.
*/
public void setMessageConverters(HttpMessageConverter>[] messageConverters) {
Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
this.messageConverters = messageConverters;
}
-
-
public boolean supports(Object handler) {
return getMethodResolver(handler).hasHandlerMethods();
}
@@ -345,32 +325,20 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
return invokeHandlerMethod(request, response, handler);
}
- protected ModelAndView invokeHandlerMethod(
- HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
+ throws Exception {
- try {
- ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
- Method handlerMethod = methodResolver.resolveHandlerMethod(request);
- ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
- ServletWebRequest webRequest = new ServletWebRequest(request, response);
- ExtendedModelMap implicitModel = new BindingAwareModelMap();
+ ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
+ Method handlerMethod = methodResolver.resolveHandlerMethod(request);
+ ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
+ ServletWebRequest webRequest = new ServletWebRequest(request, response);
+ ExtendedModelMap implicitModel = new BindingAwareModelMap();
- Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
- ModelAndView mav =
- methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
- methodInvoker.updateModelAttributes(
- handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
- return mav;
- }
- catch (NoSuchRequestHandlingMethodException ex) {
- return handleNoSuchRequestHandlingMethod(ex, request, response);
- }
- catch (HttpRequestMethodNotSupportedException ex) {
- return handleHttpRequestMethodNotSupportedException(ex, request, response);
- }
- catch (HttpMediaTypeNotSupportedException ex) {
- return handleHttpMediaTypeNotSupportedException(ex, request, response);
- }
+ Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
+ ModelAndView mav =
+ methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
+ methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
+ return mav;
}
public long getLastModified(HttpServletRequest request, Object handler) {
@@ -378,89 +346,25 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Handle the case where no request handler method was found.
- * The default implementation logs a warning and sends an HTTP 404 error.
- * Alternatively, a fallback view could be chosen, or the
- * NoSuchRequestHandlingMethodException could be rethrown as-is.
- * @param ex the NoSuchRequestHandlingMethodException to be handled
+ * Template method for creating a new ServletRequestDataBinder instance. The default implementation creates a
+ * standard ServletRequestDataBinder. This can be overridden for custom ServletRequestDataBinder subclasses.
+ *
* @param request current HTTP request
- * @param response current HTTP response
- * @return a ModelAndView to render, or The default implementation logs a warning, sends an HTTP 405 error and sets the "Allow" header.
- * Alternatively, a fallback view could be chosen, or the HttpRequestMethodNotSupportedException
- * could be rethrown as-is.
- * @param ex the HttpRequestMethodNotSupportedException to be handled
- * @param request current HTTP request
- * @param response current HTTP response
- * @return a ModelAndView to render, or The default implementation logs a warning, sends an HTTP 415 error and sets the "Allow" header.
- * Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotSupportedException
- * could be rethrown as-is.
- * @param ex the HttpMediaTypeNotSupportedException to be handled
- * @param request current HTTP request
- * @param response current HTTP response
- * @return a ModelAndView to render, or The default implementation creates a standard ServletRequestDataBinder.
- * This can be overridden for custom ServletRequestDataBinder subclasses.
- * @param request current HTTP request
- * @param target the target object to bind onto (or null.
- * null. null
- * if none (indicating that no multipart support is available)
+ *
+ * @return the MultipartResolver used by this servlet, or null if none (indicating that no multipart
+ * support is available)
*/
public final MultipartResolver getMultipartResolver() {
return this.multipartResolver;
}
-
/**
- * Return the default strategy object for the given strategy interface.
- * getLastModified method to evaluate
- * the Last-Modified value of the mapped handler.
+ * Override HttpServlet's getLastModified method to evaluate the Last-Modified value of the mapped
+ * handler.
*/
@Override
protected long getLastModified(HttpServletRequest request) {
if (logger.isDebugEnabled()) {
String requestUri = new UrlPathHelper().getRequestUri(request);
- logger.debug("DispatcherServlet with name '" + getServletName() +
- "' determining Last-Modified value for [" + requestUri + "]");
+ logger.debug(
+ "DispatcherServlet with name '" + getServletName() + "' determining Last-Modified value for [" +
+ requestUri + "]");
}
try {
HandlerExecutionChain mappedHandler = getHandler(request, true);
@@ -918,12 +858,11 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
-
/**
- * Build a LocaleContext for the given request, exposing the request's
- * primary locale as current locale.
- * null if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
- HandlerExecutionChain handler =
- (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
+ HandlerExecutionChain handler = (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
if (handler != null) {
if (!cache) {
request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
@@ -1007,6 +948,7 @@ public class DispatcherServlet extends FrameworkServlet {
/**
* No handler found -> set appropriate HTTP response status.
+ *
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception if preparing the response failed
@@ -1014,17 +956,17 @@ public class DispatcherServlet extends FrameworkServlet {
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
String requestUri = new UrlPathHelper().getRequestUri(request);
- pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" +
- requestUri + "] in DispatcherServlet with name '" + getServletName() + "'");
+ pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri +
+ "] in DispatcherServlet with name '" + getServletName() + "'");
}
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
/**
* Return the HandlerAdapter for this handler object.
+ *
* @param handler the handler object to find an adapter for
- * @throws ServletException if no HandlerAdapter can be found for the handler.
- * This is a fatal error.
+ * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
@@ -1041,17 +983,19 @@ public class DispatcherServlet extends FrameworkServlet {
/**
* Determine an error ModelAndView via the registered HandlerExceptionResolvers.
+ *
* @param request current HTTP request
* @param response current HTTP response
- * @param handler the executed handler, or null if none chosen at the time of
- * the exception (for example, if multipart resolution failed)
+ * @param handler the executed handler, or 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
* @return a corresponding ModelAndView to forward to
* @throws Exception if no error ModelAndView found
*/
- protected ModelAndView processHandlerException(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
+ protected ModelAndView processHandlerException(HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler,
+ Exception ex) throws Exception {
// Check registerer HandlerExceptionResolvers...
ModelAndView exMv = null;
@@ -1066,35 +1010,26 @@ public class DispatcherServlet extends FrameworkServlet {
return null;
}
if (logger.isDebugEnabled()) {
- logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
+ logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv,
+ ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
- // Send default responses for well-known exceptions, if possible.
- if (ex instanceof HttpRequestMethodNotSupportedException && !response.isCommitted()) {
- String[] supportedMethods = ((HttpRequestMethodNotSupportedException) ex).getSupportedMethods();
- if (supportedMethods != null) {
- response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
- }
- response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage());
- return null;
- }
-
throw ex;
}
/**
- * Render the given ModelAndView. This is the last stage in handling a request.
- * It may involve resolving the view by name.
+ * Render the given ModelAndView. This is the last stage in handling a request. It may involve resolving the view by
+ * name.
+ *
* @param mv the ModelAndView to render
* @param request current HTTP servlet request
* @param response current HTTP servlet response
* @throws Exception if there's a problem rendering the view
*/
- protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
- throws Exception {
+ protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
@@ -1106,8 +1041,9 @@ public class DispatcherServlet extends FrameworkServlet {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
- throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
- "' in servlet with name '" + getServletName() + "'");
+ throw new ServletException(
+ "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
+ getServletName() + "'");
}
}
else {
@@ -1128,6 +1064,7 @@ public class DispatcherServlet extends FrameworkServlet {
/**
* Translate the supplied request into a default view name.
+ *
* @param request current HTTP servlet request
* @return the view name (or null if no default found)
* @throws Exception if view name translation failed
@@ -1137,22 +1074,22 @@ public class DispatcherServlet extends FrameworkServlet {
}
/**
- * Resolve the given view name into a View object (to be rendered).
- * null if none found
- * @throws Exception if the view cannot be resolved
- * (typically in case of problems creating an actual View object)
+ * @throws Exception if the view cannot be resolved (typically in case of problems creating an actual View object)
* @see ViewResolver#resolveViewName
*/
- protected View resolveViewName(
- String viewName, Mapnull if none
* @see HandlerInterceptor#afterCompletion
*/
- private void triggerAfterCompletion(
- HandlerExecutionChain mappedHandler, int interceptorIndex,
- HttpServletRequest request, HttpServletResponse response, Exception ex)
- throws Exception {
+ private void triggerAfterCompletion(HandlerExecutionChain mappedHandler,
+ int interceptorIndex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Exception ex) throws Exception {
// Apply afterCompletion methods of registered interceptors.
if (mappedHandler != null) {
@@ -1196,9 +1134,9 @@ public class DispatcherServlet extends FrameworkServlet {
/**
* Restore the request attributes after an include.
+ *
* @param request current HTTP request
- * @param attributesSnapshot the snapshot of the request attributes
- * before the include
+ * @param attributesSnapshot the snapshot of the request attributes before the include
*/
private void restoreAttributesAfterInclude(HttpServletRequest request, Map attributesSnapshot) {
logger.debug("Restoring snapshot of request attributes after include");
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.properties b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.properties
index 95404a75500..c550bd71275 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.properties
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.properties
@@ -13,6 +13,8 @@ org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.m
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
+org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.handler.DefaultHandlerExceptionResolver
+
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.java
new file mode 100644
index 00000000000..a32f626da16
--- /dev/null
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2002-2009 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.servlet.handler;
+
+import java.util.Set;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.Ordered;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * Abstract base class for {@link HandlerExceptionResolver} implementations. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return whether this resolved should proceed with resolving the exception for the given request and handler
+ * @see #setMappedHandlers
+ * @see #setMappedHandlerClasses
+ */
+ protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
+ if (handler != null) {
+ if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
+ return true;
+ }
+ if (this.mappedHandlerClasses != null) {
+ for (Class handlerClass : this.mappedHandlerClasses) {
+ if (handlerClass.isInstance(handler)) {
+ return true;
+ }
+ }
+ }
+ }
+ // Else only apply if there are no explicit handler mappings.
+ return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
+ }
+
+ /**
+ * Log the given exception at warn level, provided that warn logging has been activated through the {@link
+ * #setWarnLogCategory "warnLogCategory"} property. 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
+ * @return a corresponding ModelAndView to forward to, or null for default processing
+ */
+ protected abstract ModelAndView doResolveException(HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler,
+ Exception ex);
+
+}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/DefaultHandlerExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/DefaultHandlerExceptionResolver.java
new file mode 100644
index 00000000000..03f837719aa
--- /dev/null
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/DefaultHandlerExceptionResolver.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2002-2009 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.servlet.handler;
+
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.core.Ordered;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.util.StringUtils;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
+
+/**
+ * Default implementation of the {@link org.springframework.web.servlet.HandlerExceptionResolver
+ * HandlerExceptionResolver} interface that resolves standard Spring exceptions. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ pageNotFoundLogger.warn(ex.getMessage());
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return new ModelAndView();
+ }
+
+ /**
+ * Handle the case where no request handler method was found for the particular HTTP request method. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ pageNotFoundLogger.warn(ex.getMessage());
+ String[] supportedMethods = ex.getSupportedMethods();
+ if (supportedMethods != null) {
+ response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
+ }
+ response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage());
+ return new ModelAndView();
+ }
+
+ /**
+ * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters}
+ * were found for the PUT or POSTed content. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+ Listnull if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return new ModelAndView();
+ }
+
+ /**
+ * Handle the case when a {@link org.springframework.web.bind.WebDataBinder} conversion error occurs. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleTypeMismatch(TypeMismatchException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return new ModelAndView();
+ }
+
+ /**
+ * Handle the case where a {@linkplain org.springframework.http.converter.HttpMessageConverter message converter} can
+ * not read from a HTTP request. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return new ModelAndView();
+ }
+
+ /**
+ * Handle the case where a {@linkplain org.springframework.http.converter.HttpMessageConverter message converter} can
+ * not write to a HTTP request. null if none chosen at the time of the exception (for example,
+ * if multipart resolution failed)
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception an Exception that should be thrown as result of the servlet request
+ */
+ protected ModelAndView handleHttpMessageNotWritable(HttpMessageNotWritableException ex,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler) throws Exception {
+
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return new ModelAndView();
+ }
+
+}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java
index 8a5fade1ea0..f2f7affef7c 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java
@@ -18,51 +18,29 @@ package org.springframework.web.servlet.handler;
import java.util.Enumeration;
import java.util.Properties;
-import java.util.Set;
-
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.core.Ordered;
-import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.WebUtils;
/**
- * {@link org.springframework.web.servlet.HandlerExceptionResolver} implementation
- * that allows for mapping exception class names to view names, either for a
- * set of given handlers or for all handlers in the DispatcherServlet.
+ * {@link org.springframework.web.servlet.HandlerExceptionResolver} implementation that allows for mapping exception
+ * class names to view names, either for a set of given handlers or for all handlers in the DispatcherServlet.
*
- * javax.servlet.ServletException and subclasses, for example.
- * javax.servlet.ServletException and subclasses, for example. null for not exposing an exception attribute at all.
+ * Set the name of the model attribute as which the exception should be exposed. Default is "exception". null for not exposing an exception attribute at all.
+ *
* @see #DEFAULT_EXCEPTION_ATTRIBUTE
*/
public void setExceptionAttribute(String exceptionAttribute) {
this.exceptionAttribute = exceptionAttribute;
}
-
/**
- * Checks whether this resolver is supposed to apply (i.e. the handler
- * matches in case of "mappedHandlers" having been specified), then
- * delegates to the {@link #doResolveException} template method.
- */
- public ModelAndView resolveException(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
-
- if (shouldApplyTo(request, handler)) {
- return doResolveException(request, response, handler, ex);
- }
- else {
- return null;
- }
- }
-
- /**
- * Check whether this resolver is supposed to apply to the given handler.
- * null if none chosen at the
- * time of the exception (for example, if multipart resolution failed)
- * @return whether this resolved should proceed with resolving the exception
- * for the given request and handler
- * @see #setMappedHandlers
- * @see #setMappedHandlerClasses
- */
- protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
- if (handler != null) {
- if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
- return true;
- }
- if (this.mappedHandlerClasses != null) {
- for (Class handlerClass : this.mappedHandlerClasses) {
- if (handlerClass.isInstance(handler)) {
- return true;
- }
- }
- }
- }
- // Else only apply if there are no explicit handler mappings.
- return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
- }
-
- /**
- * Actually resolve the given exception that got thrown during on handler execution,
- * returning a ModelAndView that represents a specific error page if appropriate.
- * null if none chosen at the
- * time of the exception (for example, if multipart resolution failed)
+ * @param handler the executed handler, or 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
* @return a corresponding ModelAndView to forward to, or null for default processing
*/
- protected ModelAndView doResolveException(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
-
- // Log exception, both at debug log level and at warn level, if desired.
- if (logger.isDebugEnabled()) {
- logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
- }
- logException(ex, request);
+ @Override
+ protected ModelAndView doResolveException(HttpServletRequest request,
+ HttpServletResponse response,
+ Object handler,
+ Exception ex) {
// Expose ModelAndView for chosen error view.
String viewName = determineViewName(ex, request);
@@ -268,40 +135,10 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
}
-
/**
- * Log the given exception at warn level, provided that warn logging has been
- * activated through the {@link #setWarnLogCategory "warnLogCategory"} property.
- * null if none found
@@ -315,8 +152,8 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
// Return default error view else, if defined.
if (viewName == null && this.defaultErrorView != null) {
if (logger.isDebugEnabled()) {
- logger.debug("Resolving to default view '" + this.defaultErrorView +
- "' for exception of type [" + ex.getClass().getName() + "]");
+ logger.debug("Resolving to default view '" + this.defaultErrorView + "' for exception of type [" +
+ ex.getClass().getName() + "]");
}
viewName = this.defaultErrorView;
}
@@ -325,6 +162,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
/**
* Find a matching view name in the given exception mappings.
+ *
* @param exceptionMappings mappings between exception class names and error view names
* @param ex the exception that got thrown during handler execution
* @return the view name, or null if none found
@@ -351,11 +189,9 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
/**
- * Return the depth to the superclass matching.
- * null for the
- * servlet container's default (200 in case of a standard error view)
+ * @return the HTTP status code to use, or null for the servlet container's default (200 in case of a
+ * standard error view)
* @see #setDefaultStatusCode
* @see #applyStatusCodeIfPossible
*/
@@ -392,8 +226,9 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
/**
- * Apply the specified HTTP status code to the given response, if possible
- * (that is, if not executing within an include request).
+ * Apply the specified HTTP status code to the given response, if possible (that is, if not executing within an include
+ * request).
+ *
* @param request current HTTP request
* @param response current HTTP response
* @param statusCode the status code to apply
@@ -412,8 +247,9 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
/**
- * Return a ModelAndView for the given request, view name and exception.
- * @RequestMapping annotation).
- * @RequestMapping annotation). @SessionAttributes annotated handlers
- * for the given number of seconds. Default is 0, preventing caching completely.
- * @SessionAttributes annotated handlers), this
- * setting will apply to @SessionAttributes annotated handlers only.
+ * Cache content produced by @SessionAttributes annotated handlers for the given number of seconds.
+ * Default is 0, preventing caching completely. @SessionAttributes annotated handlers), this setting will apply to
+ * @SessionAttributes annotated handlers only.
+ *
* @see #setCacheSeconds
* @see org.springframework.web.bind.annotation.SessionAttributes
*/
@@ -254,20 +245,15 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
/**
- * Set if controller execution should be synchronized on the session,
- * to serialize parallel invocations from the same client.
- * SESSION_MUTEX_ATTRIBUTE constant. It serves as a
- * safe reference to synchronize on for locking on the current session.
- * SESSION_MUTEX_ATTRIBUTE constant. It serves as a safe
+ * reference to synchronize on for locking on the current session. null if handled directly
- * @throws Exception an Exception that should be thrown as result of the servlet request
- */
- protected ModelAndView handleNoSuchRequestHandlingMethod(
- NoSuchRequestHandlingMethodException ex, HttpServletRequest request, HttpServletResponse response)
- throws Exception {
-
- pageNotFoundLogger.warn(ex.getMessage());
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- return null;
- }
-
- /**
- * Handle the case where no request handler method was found for the particular HTTP request method.
- * null if handled directly
- * @throws Exception an Exception that should be thrown as result of the servlet request
- */
- protected ModelAndView handleHttpRequestMethodNotSupportedException(
- HttpRequestMethodNotSupportedException ex, HttpServletRequest request, HttpServletResponse response)
- throws Exception {
-
- pageNotFoundLogger.warn(ex.getMessage());
- response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
- response.addHeader("Allow", StringUtils.arrayToDelimitedString(ex.getSupportedMethods(), ", "));
- return null;
- }
-
- /**
- * Handle the case where no {@linkplain HttpMessageConverter message converters} was found for the PUT or POSTed
- * content.
- * null if handled directly
- * @throws Exception an Exception that should be thrown as result of the servlet request
- */
- protected ModelAndView handleHttpMediaTypeNotSupportedException(
- HttpMediaTypeNotSupportedException ex, HttpServletRequest request, HttpServletResponse response)
- throws Exception {
-
- response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
- response.addHeader("Accept", MediaType.toString(ex.getSupportedMediaTypes()));
- return null;
- }
-
- /**
- * Template method for creating a new ServletRequestDataBinder instance.
- * null
- * if the binder is just used to convert a plain parameter value)
+ * @param target the target object to bind onto (or null if the binder is just used to convert a plain
+ * parameter value)
* @param objectName the objectName of the target object
* @return the ServletRequestDataBinder instance to use
* @throws Exception in case of invalid state or arguments
* @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest)
* @see ServletRequestDataBinder#convertIfNecessary(Object, Class, MethodParameter)
*/
- protected ServletRequestDataBinder createBinder(
- HttpServletRequest request, Object target, String objectName) throws Exception {
+ protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName)
+ throws Exception {
return new ServletRequestDataBinder(target, objectName);
}
- /**
- * Build a HandlerMethodResolver for the given handler type.
- */
+ /** Build a HandlerMethodResolver for the given handler type. */
private ServletHandlerMethodResolver getMethodResolver(Object handler) {
Class handlerClass = ClassUtils.getUserClass(handler);
ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);
@@ -471,10 +375,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
return resolver;
}
-
- /**
- * Servlet-specific subclass of {@link HandlerMethodResolver}.
- */
+ /** Servlet-specific subclass of {@link HandlerMethodResolver}. */
private class ServletHandlerMethodResolver extends HandlerMethodResolver {
private ServletHandlerMethodResolver(Class> handlerType) {
@@ -499,7 +400,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
}
boolean match = false;
if (mappingInfo.paths.length > 0) {
- List
- *