The challenge
I have been getting complaints from people who were trying to suggest a podcast to Podcastpedia.org, and that for a good reason. They were getting a page with the following message:
"Unknown error. Please inform us about it with the Error indication form."
This is the default page rendered when an unknown exception occurs. Although this is prettier than displaying the error stacktrace, it should be avoided – it didn’t tell the visitors much and me neither.
Image may be NSFW.
Clik here to view.
Source code for this post is available on Github - podcastpedia.org is an open source project.
I have been struggling with this for some time and couldn’t find the reason, because everytime I would fill the form with the same input provided by the visitors it would work perfectly for me. Until today, when somehow the session expiration setting popped into my mind. I recalled setting the session timeout pretty short – 1 minute (default in Tomcat is 30 minutes) – in the web.xml
file, for “performance” reasons:
<!-- set session timeout for 1 minute <url-pattern>/*.atom</url-pattern> --> <session-config> <session-timeout>1</session-timeout> <tracking-mode>COOKIE</tracking-mode> </session-config>
I have to admit one minute is extremly short. So I filled the form, waited 1 min and 13 seconds et voilà, I got the same error when trying to submit.
The Spring controller handling the podcast submission form uses the @SessionAttributes("addPodcastForm")
annotation. This indicates the model object – addPodcastForm
– to be held in a session, so that if a validation error ocurs, the visitor doesn’t have to fill the fields all over again. This annotation forces the existence of a valid session and triggered the error message.
The solution
Modify session-timeout in web.xml
So the actual fix for this challenge was pretty easy, I’ve just increased the session-timeout
value from 1 to 10 minutes. But what if a visitor starts filling the form, goes away, drinks a coffee and returns to submit the form after 15 minutes, I wouldn’t want her to see the same "Unknown error..."
message – one pointing to the error cause and how the user might react would be much better.
Meet the @ExceptionHandler
Well, Spring isn’t considered a mighty framework for nothing. To catch such an exception all I had to do is annotate a method in the controller, which handles the form submission requests, with @ExceptionHandler
and specify which type of Exception to handle:
@ExceptionHandler(HttpSessionRequiredException.class) @ResponseStatus(value = HttpStatus.UNAUTHORIZED, reason="The session has expired")) public String handleSessionExpired(){ return "sessionExpired"; }
The HttpSessionRequiredException
requires a pre-existing session. The @ResponseStatus
is optional and marks the method with the status code and the reason that should be returned. Several return types are supported for handler methods, but when I return a String – sessionExpired
– this value is interpreted as a view name. In the Tiles configuration there is a definition which, based on this name, renders now a page with a corresponding message for session expiration.
Note: Please see my post Spring MVC and Apache Tiles integration example for an explanation of using Tiles definitions with Spring MVC.
Exception handling configuration in the application context
............ <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver" p:order="1" /> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:order="2" p:defaultErrorView="uncaughtException"> <property name="exceptionMappings"> <props> <prop key="org.springframework.core.NestedRuntimeException.DataAccessException">dataAccessFailure</prop> <prop key="org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException">resourceNotFound</prop> <prop key="org.springframework.beans.TypeMismatchException">resourceNotFound</prop> <prop key="org.springframework.web.bind.MissingServletRequestParameterException">resourceNotFound</prop> </props> </property> </bean> ............
The exception handling is configured in the application context via
ExceptionHandler
– resolves exceptions through@ExceptionHandler
methods as our above method. It is configured to take precedence because thep:order
to 1.SimpleMappingExceptionResolver
– allows for mapping exception class names to view names, either for a set of given handlers or for all handlers in the DispatcherServlet. Notice here thedefaultErrorView
attribute which sets the name of the default error view, if no specific mapping was found – this was the case for the session timeout exception.
Well, that’s it. I hope you could learn something from this as I did.
Image may be NSFW.
Clik here to view.
Source code for this post is available on Github - podcastpedia.org is an open source project.
Resources
Adrian’s favorite Spring and Java books (affiliate links)