With a little prodding from Erik Hatcher today, I took another look at Struts' Declared Exceptions feature. At the end of last year, I was wishing I could use declared exceptions to do chained exceptions for my Action classes. Basically, in each of my Actions, I have a try/catch wrapped around a call to the Business Delegate (example: UserAction.java). You'll notice that all the CRUD methods have the same catch block for exception handling:
} catch (Exception e) {
e.printStackTrace();
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("errors.general"));
while (e != null) {
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("errors.detail", e.getMessage()));
e = (Exception) e.getCause();
}
saveErrors(request, errors);
return mapping.getInputForward();
}
After talking with Erik this morning, I decided to create an ActionExceptionHandler for java.lang.Exception
. In my struts-config.xml, I added:
<exception type="java.lang.Exception" key="errors.general"
handler="org.appfuse.webapp.action.ActionExceptionHandler"/>
I have "errors.general=The process did not complete. Details should follow." Here is the code for ActionExceptionHandler:
public final class ActionExceptionHandler extends ExceptionHandler {
public ActionForward execute(Exception ex, ExceptionConfig ae,
ActionMapping mapping,
ActionForm formInstance,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException {
ActionForward forward = null;
ActionError error = null;
ActionErrors errors = new ActionErrors();
String property = null;
// Build the forward from the exception mapping if it exists
// or from the form input
if (ae.getPath() != null) {
forward = new ActionForward(ae.getPath());
} else {
forward = mapping.getInputForward();
}
ex.printStackTrace();
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError(error.getKey()));
while (ex != null) {
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("errors.detail", ex.getMessage()));
ex = (Exception) ex.getCause();
}
// Store the errors and exception
request.setAttribute(Globals.ERROR_KEY, errors);
return forward;
}
}
This allows me to remove my generic try/catches from my action classes - very slick IMO (or at least better than the code smell I had)! Of course, I still have some catch blocks that catch specific exceptions, but I can either (1) leave those intact, or (2) create another declared exception for that particular action/exception. I dig it and will be adding it (in short order) to AppFuse.
Update (June 23, 2003): Here's a more thoroughly tested code sample of this same class.
I'm starting to think that my Struts-based apps could be simplified if I didn't convert POJOs to Action Forms when retrieving them from the database. By this, I mean to say that I'd like to retrieve and display POJOs on the UI, and then capture their information (as Action Forms) when saving the form. The reason I want to do this is because of Hibernate's Lazy Loading feature and formatting Dates. Basically, Hibernate allows you to load children of an object lazily (i.e. resumes of a User), when the getResumes() method is called.
I've created [a page|POJOsToForms] on my wiki to explain further and continue this discussion. Of course, you can always leave comments here if you'd rather - they cross-reference each other. The [RollingWiki|http://www.rollerweblogger.org/wiki/Wiki.jsp?page=RollerWikiPlugin] rocks!