Web Applications can generate exceptions and unfortunately the Servlet specification's built-in exception handling mechanism is somewhat limited. Specifically it can only forward the user to an alternative JSP or file; it cannot forward to a servlet or cause non-JSP code to be executed. This is what the Stripes exception handling mechanism aims to solve.
Most of the major interfaces in Stripes allow developers to throw any exceptions they don't want to handle. Handler methods, validation methods, etc. call all throw Throwable! It's up to you to define your exception handling strategy: Stripes will not impose one on you. That said, it's the author's opinion that you should generally propagate (not catch, wrap and throw) any exception that you can't handle, and let the framework take care of it.
The starting point is the ExceptionHandler interface. Implementations of this interface are used to handle any exceptions that arise during a request. They may rethrow exceptions, or execute arbitrary code and return a Resolution to tell Stripes what to do next.
|The ExceptionHandler is invoked from the Stripes Filter. This allows it to handle exceptions generated in ActionBeans, in JSPs and even in other Servlet Filters that are lower down the chain than the Stripes Filter.|
The DefaultExceptionHandler used by Stripes doesn't do much! If the exception being handled is a ServletException it is rethrown, otherwise it is wrapped in a StripesServletException and rethrown. That's it!
However, by extending DefaultExceptionHandler, you can easily handle different types of exceptions in different ways. All you have to do is add methods, arbitrarily named, that accept exactly 3 parameters: the exception type, the HTTP request, and the HTTP response. Furthermore, if the method returns a Resolution, it will be executed. For example:
When an exception is handled the DefaultExceptionHandler looks for the most specific method to handle the exception. If it cannot find one that handles the exact exception type thrown, it will look for a method that handles the parent type and so on up the hierarchy. If no handler can be found, then the exception is rethrown. For this reason it is recommended to always have a handler method that takes Exception.
The DelegatingExceptionHandler works similarly to the DefaultExceptionHandler described above, but lets you write more than one class that handles exceptions. Each of those classes must implement the AutoExceptionHandler marker interface.
AutoExceptionHandlers can have one or more methods with the same signature as described earlier:
When it is initialized the DelegatingExceptionHandler scans the classpath to find all instances of AutoExceptionHandler. These will be found either in the packages configured in the DelegatingExceptionHandler.Packages Stripes Filter init-param, or the more general Extension.Packages.
Writing your own exception handler is quite straightforward. The class simply has to implement ExceptionHandler interface, which specifies two methods (including the inherited one). For example:
Even easier is to extend DefaultExceptionHandler and add exception-handling methods as described above.
Having created your own exception handler, you'll need to configure it. You can do this either by placing your class in a package that's configured as an extensions package (see Extensions), or by using the ExceptionHandler.Class parameter, e.g.
The interface of ExceptionHandler is quite basic:
This is primarily because the exception handler can handle exceptions from anywhere in a Stripes application - even prior to things like the ActionBean and ActionBeanContext having been created! The interface of AutoExceptionHandler is similar. This may leave you wondering how to get access to the ActionBean etc. should one be present. For example you may know, based on the type of exception being handled, that it had to originate from an ActionBean. Or you might simply wish to handle things differently if an ActionBean is present.
Checking for and retrieving an ActionBean is relatively simple, and through it the ActionBeanContext, ValidationErrors etc. For example: