Matt RaibleMatt Raible is a Java Champion and Developer Advocate at Okta.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Using Struts' Declared Exceptions

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: You'll notice that all the CRUD methods have the same catch block for exception handling:

} catch (Exception e) {
               new ActionError("errors.general"));

    while (e != null) {
                   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"

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();

        errors.add(ActionErrors.GLOBAL_ERROR, new ActionError(error.getKey()));

        while (ex != null) {
                       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.

Posted in Java at Jun 19 2003, 05:55:20 PM MDT 3 Comments

What was wrong with using the built-in ExceptionHandler rather than writing your own? I'd recommend using the built-in one if you can.

Posted by Erik Hatcher on June 19, 2003 at 06:17 PM MDT #

The problem I have with the built-in one is that it doesn't support chained exceptions. Rather it will only grab the message from the top-most exception. My chained exceptions implementation is derived from From Ted Husted's use chained exceptions tip. By doing this, the error displayed will not be simply, "Could not connect to database.", but rather:

* Could not connect to database.
* Cannot connect to MySQL server localhost:3307. Is there a MySQL
  server running the machine/port you are trying to connect to? 

This gives the user the generic user-friendly message they desire (the first one), and also allows the support team to realize exactly what went wrong.

Posted by Matt Raible on June 19, 2003 at 06:43 PM MDT #

Ah.... gotcha. I don't want that much detail shown to our users though. Its just our own ValidationExceptions that get thrown to pages this way. If our SystemException happens, we bounce to error.jsp which has the full stack trace shown in an HTML comment.

Posted by Erik Hatcher on June 19, 2003 at 07:16 PM MDT #

Post a Comment:
  • HTML Syntax: Allowed