Skip to content

Commit 161c926

Browse files
committed
SPR-5624 - A default HandlerExceptionResolver that resolves standard Spring exceptions
1 parent f92b7f1 commit 161c926

File tree

9 files changed

+1096
-782
lines changed

9 files changed

+1096
-782
lines changed

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.java

+214-276
Large diffs are not rendered by default.

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.properties

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.m
1313
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
1414
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
1515

16+
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.handler.DefaultHandlerExceptionResolver
17+
1618
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
1719

1820
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* Copyright 2002-2009 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.handler;
18+
19+
import java.util.Set;
20+
import javax.servlet.http.HttpServletRequest;
21+
import javax.servlet.http.HttpServletResponse;
22+
23+
import org.apache.commons.logging.Log;
24+
import org.apache.commons.logging.LogFactory;
25+
26+
import org.springframework.core.Ordered;
27+
import org.springframework.web.servlet.HandlerExceptionResolver;
28+
import org.springframework.web.servlet.ModelAndView;
29+
30+
/**
31+
* Abstract base class for {@link HandlerExceptionResolver} implementations. <p>Provides a set of mapped handlers that
32+
* the resolver should map to, and the {@link Ordered} implementation.
33+
*
34+
* @author Arjen Poutsma
35+
* @since 3.0
36+
*/
37+
public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
38+
39+
/** Logger available to subclasses */
40+
protected final Log logger = LogFactory.getLog(getClass());
41+
42+
private int order = Ordered.LOWEST_PRECEDENCE;
43+
44+
private Set mappedHandlers;
45+
46+
private Class[] mappedHandlerClasses;
47+
48+
private Log warnLogger;
49+
50+
public void setOrder(int order) {
51+
this.order = order;
52+
}
53+
54+
public int getOrder() {
55+
return this.order;
56+
}
57+
58+
/**
59+
* Specify the set of handlers that this exception resolver should apply to. The exception mappings and the default
60+
* error view will only apply to the specified handlers. <p>If no handlers and handler classes are set, the exception
61+
* mappings and the default error view will apply to all handlers. This means that a specified default error view will
62+
* be used as fallback for all exceptions; any further HandlerExceptionResolvers in the chain will be ignored in this
63+
* case.
64+
*/
65+
public void setMappedHandlers(Set mappedHandlers) {
66+
this.mappedHandlers = mappedHandlers;
67+
}
68+
69+
/**
70+
* Specify the set of classes that this exception resolver should apply to. The exception mappings and the default
71+
* error view will only apply to handlers of the specified type; the specified types may be interfaces and superclasses
72+
* of handlers as well. <p>If no handlers and handler classes are set, the exception mappings and the default error
73+
* view will apply to all handlers. This means that a specified default error view will be used as fallback for all
74+
* exceptions; any further HandlerExceptionResolvers in the chain will be ignored in this case.
75+
*/
76+
public void setMappedHandlerClasses(Class[] mappedHandlerClasses) {
77+
this.mappedHandlerClasses = mappedHandlerClasses;
78+
}
79+
80+
/**
81+
* Set the log category for warn logging. The name will be passed to the underlying logger implementation through
82+
* Commons Logging, getting interpreted as log category according to the logger's configuration. <p>Default is no warn
83+
* logging. Specify this setting to activate warn logging into a specific category. Alternatively, override the {@link
84+
* #logException} method for custom logging.
85+
*
86+
* @see org.apache.commons.logging.LogFactory#getLog(String)
87+
* @see org.apache.log4j.Logger#getLogger(String)
88+
* @see java.util.logging.Logger#getLogger(String)
89+
*/
90+
public void setWarnLogCategory(String loggerName) {
91+
this.warnLogger = LogFactory.getLog(loggerName);
92+
}
93+
94+
/**
95+
* Checks whether this resolver is supposed to apply (i.e. the handler matches in case of "mappedHandlers" having been
96+
* specified), then delegates to the {@link #doResolveException} template method.
97+
*/
98+
public ModelAndView resolveException(HttpServletRequest request,
99+
HttpServletResponse response,
100+
Object handler,
101+
Exception ex) {
102+
103+
if (shouldApplyTo(request, handler)) {
104+
// Log exception, both at debug log level and at warn level, if desired.
105+
if (logger.isDebugEnabled()) {
106+
logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
107+
}
108+
logException(ex, request);
109+
return doResolveException(request, response, handler, ex);
110+
}
111+
else {
112+
return null;
113+
}
114+
}
115+
116+
/**
117+
* Check whether this resolver is supposed to apply to the given handler. <p>The default implementation checks against
118+
* the specified mapped handlers and handler classes, if any.
119+
*
120+
* @param request current HTTP request
121+
* @param handler the executed handler, or <code>null</code> if none chosen at the time of the exception (for example,
122+
* if multipart resolution failed)
123+
* @return whether this resolved should proceed with resolving the exception for the given request and handler
124+
* @see #setMappedHandlers
125+
* @see #setMappedHandlerClasses
126+
*/
127+
protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
128+
if (handler != null) {
129+
if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
130+
return true;
131+
}
132+
if (this.mappedHandlerClasses != null) {
133+
for (Class handlerClass : this.mappedHandlerClasses) {
134+
if (handlerClass.isInstance(handler)) {
135+
return true;
136+
}
137+
}
138+
}
139+
}
140+
// Else only apply if there are no explicit handler mappings.
141+
return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
142+
}
143+
144+
/**
145+
* Log the given exception at warn level, provided that warn logging has been activated through the {@link
146+
* #setWarnLogCategory "warnLogCategory"} property. <p>Calls {@link #buildLogMessage} in order to determine the
147+
* concrete message to log. Always passes the full exception to the logger.
148+
*
149+
* @param ex the exception that got thrown during handler execution
150+
* @param request current HTTP request (useful for obtaining metadata)
151+
* @see #setWarnLogCategory
152+
* @see #buildLogMessage
153+
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
154+
*/
155+
protected void logException(Exception ex, HttpServletRequest request) {
156+
if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
157+
this.warnLogger.warn(buildLogMessage(ex, request), ex);
158+
}
159+
}
160+
161+
/**
162+
* Build a log message for the given exception, occured during processing the given request.
163+
*
164+
* @param ex the exception that got thrown during handler execution
165+
* @param request current HTTP request (useful for obtaining metadata)
166+
* @return the log message to use
167+
*/
168+
protected String buildLogMessage(Exception ex, HttpServletRequest request) {
169+
return "Handler execution resulted in exception";
170+
}
171+
172+
/**
173+
* Actually resolve the given exception that got thrown during on handler execution, returning a ModelAndView that
174+
* represents a specific error page if appropriate. <p>May be overridden in subclasses, in order to apply specific
175+
* exception checks. Note that this template method will be invoked <i>after</i> checking whether this resolved applies
176+
* ("mappedHandlers" etc), so an implementation may simply proceed with its actual exception handling.
177+
*
178+
* @param request current HTTP request
179+
* @param response current HTTP response
180+
* @param handler the executed handler, or <code>null</code> if none chosen at the time of the exception (for example,
181+
* if multipart resolution failed)
182+
* @param ex the exception that got thrown during handler execution
183+
* @return a corresponding ModelAndView to forward to, or <code>null</code> for default processing
184+
*/
185+
protected abstract ModelAndView doResolveException(HttpServletRequest request,
186+
HttpServletResponse response,
187+
Object handler,
188+
Exception ex);
189+
190+
}

0 commit comments

Comments
 (0)