> Home

Errors and Messages

Holiday Accommodation in Croatia

I originally wrote this page is to compare the use of the Struts <html:errors> and <html:messages> tags - but its expanded beyond that. This page now contans the following sections...

1. Why have two JSP tags that do the same job?

The reason that the <html:messages> tag was introduced was because some people didn't like the fact that using <html:errors> required HTML markup in their message resources. Using <html:messages> removes this requirement. Examples below show the differences between the two approaches.

MISCONCEPTION: Some people mistakenly connect these two tags with the fact that ActionMessage/ActionMessages were introduced to replace ActionError/ActionErrors. This is NOT the case and <html:errors> is NOT deprecated in favour of <html:messages> - both are valid approaches to achieve the same goal, its just a matter of preference which one you use. If you're looking to understand the ActionError/ActionErrors and ActionMessage/ActionMessages issues, then see the Struts Wiki.

top

2. Example Usage of Errors and Messages Tags

N.B. For full details of all the attributes for the <html:errors> and <html:messages> tags see the HTML Taglib User Guide.

Say you want your messages formatted in the following way:

   <h3><font color="red">Validation Errors</font></h3>
       <ul>
           <li>First Message</li>
           <li>Second Message</li>
           <li>....etc.</li>
       </ul>

2.1 Example 1: <html:errors>

Simply add the <html:errors> tag to your JSP page...

   <html:errors />

...and define the appropriate keys in your messages resources....

errors.header=<h3><font color="red">Validation Errors</font></h3><ul>
errors.footer=</ul>
errors.prefix=<li>
errors.suffix=</li>

myForm.message1=First Message
myForm.message2=Second Message

The <html:errors /> tag renders the values specified for keys errors.header and errors.footer at the start and end of the messages respectively and renders the values specified for keys errors.prefix and errors.suffix before and after each message respectively.

N.B.One problem with the <html:errors/> tag that <html:messages> overcame was the fact that the keys for the header, footer, prefix and suffix could not be changed, which meant you were stuck with the same format for the whole application. Since Struts Version 1.2.5 alternative keys can be specified for the header, footer, prefix and suffix on the <html:errors /> tag using attributes with those names. See here for an example.

2.2 Example 2: <html:messages>

Add the <html:messages> tag to your JSP page...

   <logic:messagesPresent>

       <h3><font color="red"><bean:message key="myForm.error.header" /></font></h3>
           <ul>
               <html:messages id="msg">
                   <li><bean:write name="msg" /></li>
               </html:messages>
           </ul>

   </logic:messagesPresent>

...and define the appropriate keys in your messages resources....

myForm.error.header=Validation Errors
myForm.message1=First Message
myForm.message2=Second Message

The way that the <html:messages/> tag works is that it simply iterates over the collection of messages and makes them available to the body of the tag by storing them under a page scope variable that is named according to what you specify in the id attribute - in this example msg. It doesn't actually render the message - you also have to use a <bean:write> (or the JSTL <c:out>) tag to render the message.

This does have the benefit of keeping the HTML markup all on the jsp page and out of the message resources, but is far more complex than using the <html:errors /> tag.

top

3. Further Errors/Messages Tag Examples

3.1 Example 3: <html:errors> and Alternative Keys

Since Struts Version 1.2.5 it is possible to specify alternative keys for the header, footer, prefix and suffix used by <html:errors>, rather than having to use errors.header, errors.footer, errors.prefix and errors.suffix. for every page.

   <html:errors header="mfForm.header"
                   footer="mfForm.footer"
                   prefix="mfForm.prefix"
                   suffix="mfForm.suffix" />

...and define the appropriate keys in your messages resources....

mfForm.header=<h3><font color="red">Validation Errors</font></h3><ul>
mfForm.footer=</ul>
mfForm.prefix=<li>
mfForm.suffix=</li>

myForm.message1=First Message
myForm.message2=Second Message

3.2 Example 4: Using <logic:messagesPresent> with <html:errors>

Using the <logic:messagesPresent> tag with <html:errors> can be used to get most of the HTML markup out of the messages resources, in the same way as its used with <html:messages>

On the JSP page...

   <logic:messagesPresent>

       <h3><font color="red"><bean:message key="myForm.error.header" /></font></h3>
           <ul>
              <html:errors />
           </ul>

   </logic:messagesPresent>

Define the appropriate keys in your messages resources, but make sure the errors.header and errors.header keys don't exist or are removed from your message resources...

errors.prefix=<li>
errors.suffix=</li>

myForm.error.header=Validation Errors
myForm.message1=First Message
myForm.message2=Second Message

3.3 Example 5: <html:messages> Header and Footer attributes

Header and Footer attributes can be specified for the <html:messages> tag and work in the same way as <html:errors>

On the JSP page...

    <html:messages id="msg" header="myForm.header" footer="myForm.footer">
        <li><bean:write name="msg" /></li>
    </html:messages>

...and define the appropriate keys in your messages resources....

myForm.header=<h3><font color="red">Validation Errors</font></h3><ul>
myForm.footer=</ul>

myForm.message1=First Message
myForm.message2=Second Message

This is really only included for completeness, since it puts the HTML markup back in the messages resources and is more complex than <html:errors> equivalent. Personally, I don't understand the thinking behind having these attributes on the <html:messages> tag.

top

4. How Do the Tags Find the Messages?

This section describes how the <html:errors> and <html:messages> tags find the collection of messages to display.

4.1 The Default - Validation Errors

The ActionErrors returned from the ActionForm's validate(ActionMapping, HttpServletRequest) method are stored by Struts in the request under the key specified by Globals.ERROR_KEY. By default, both the <html:errors> and <html:messages> tags retrieve the messages using this key.

If you prefer to put the validation in your Action (rather than the ActionForm's validate() method) then a convenience method is provided which will store them under this key. So you might have something like the following in your Action's execute() method...

        if (<insert-condition-here>) {
            ActionMessages errors = new ActionMessages();
            errors.add("myProperty",
                       new ActionMessage("myProperty.error"));
            saveErrors(request, errors);
        }

All the saveErrors() method is doing is saving you the trouble of writing the following..

        request.setAttribute(Globals.ERROR_KEY, errors);

4.2 Using a Custom Key

If you want the <html:errors> and <html:messages> to use a different key to find the stored messages then you can do this by specifying the name attribute on these tags.

For example, if you store some messages in your Action's execute method...

        ActionMessages messages = new ActionMessages();
        messages.add("STATUS", new ActionMessage("status.good"));
        messages.add("ACTION", new ActionMessage("action.next"));
        request.setAttribute("MY_MESSAGES_KEY", messages);

...using the <html:errors> tag...

   <html:errors name="MY_MESSAGES_KEY" />

...or using the <html:messages> tag...

   <html:messages id="msg" name="MY_MESSAGES_KEY">
       <li><bean:write name="msg" /></li>
   </html:messages>

4.3 Standard Messages Key

There is also a standard messages key specified by Globals.MESSAGE_KEY - and an associated convenience method in Action which will store messages in the request under this key - saveMessages(). The <html:messages> tag has a mechanism for displaying messages under this key, but the <html:errors> tag does not.

If we now, re-do the example show previously in section 4.2 using the standard messages key...

        ActionMessages messages = new ActionMessages();
        messages.add("STATUS", new ActionMessage("status.good"));
        messages.add("ACTION", new ActionMessage("action.next"));
        saveMessages(request, messages);

...using the <html:errors> tag, you have to specify the actual key defined in Globals.MESSAGE_KEY...

   <html:errors name="org.apache.struts.action.ACTION_MESSAGE" />

...but using the <html:messages> tag you can use the message attribute...

   <html:messages id="msg" message="true">
       <li><bean:write name="msg" /></li>
   </html:messages>

top

5. How To Use the Property Attribute

Take the following example....

        ActionMessages errors = new ActionMessages();
        errors.add("custNo", new ActionMessage("custNo.invalid"));
        errors.add("custName", new ActionMessage("custName.invalid"));
        errors.add("custAddress", new ActionMessage("customerAddress.invalid"));
        request.setAttribute(Globals.ERROR_KEY, errors);

You may have been wondering what the value of the first parameter in the ActionMessages's add() method is for (i.e. custNo, custName and custAddress in the above example). Thats the property - all messages are associated with a property which can then be used by the <html:messages> and <html:errors> tags to display sub-sets of messages.

If, for example, you wanted to display validation messages next to the field they relate to (rather than a single list showing all the messages) you could do that with <html:errors> in the following way...

   <html:form action="...">
       <table>
           <tr>
              <td>Customer Number:</td>
              <td><html:text property="custNo" /></td>
              <td><html:errors property="custNo" /></td>
           </tr>

           <tr>
              <td>Customer Name:</td>
              <td><html:text property="custName" /></td>
              <td><html:errors property="custName" /></td>
           </tr>

           <tr>
              <td>Customer Address:</td>
              <td><html:text property="custAddress" /></td>
              <td><html:errors property="custAddress" /></td>
           </tr>
       </table>
   </html:form>

...or using <html:messages>...

   <html:form action="...">
       <table>
           <tr>
              <td>Customer Number:</td>
              <td><html:text property="custNo" /></td>
              <td><html:messages id="msg" property="custNo">
                      <bean:write name="msg" />
                  </html:messages>
              </td>
           </tr>

           <tr>
              <td>Customer Name:</td>
              <td><html:text property="custName" /></td>
              <td><html:messages id="msg" property="custName">
                      <bean:write name="msg" />
                  </html:messages>
              </td>
           </tr>

           <tr>
              <td>Customer Address:</td>
              <td><html:text property="custAddress" /></td>
              <td><html:messages id="msg" property="custAddress">
                      <bean:write name="msg" />
                  </html:messages>
              </td>
           </tr>
       </table>
   </html:form>

On a related topic, the new Struts Error Highlighting feature also uses the errors stored under the Globals.ERROR_KEY and the message's property to apply CSS styles in the event of a validation error - so you can have the fields with errors highlighting in red, for example.

top

6. Message Bundles

Message Resources can quickly get very large and you may want to split them down into a number of files to make them more manageable. You can do this using the bundle feature.

6.1 Default Bundle

If we start with the how a single, default bundle is defined. In your struts-config.xml...

     <message-resource parameter="myPackage.ApplicationResources" null="false" />

N.B. The thing that makes the above example the default bundle is the fact that NO key has been specified. Also I recommend always using the null="false" attribute - in the event that you forgotten to add a message to your properties file(s) - or have a typo in the message's key it returns a message in the format ???en_US.myMessage.key??? rather than null .

Then you set up the different properties files for each locale...

All the examples in the previous section are using the default bundle.

6.2 Multiple Bundles

OK, now on to alternative bundles. Say you want to divide you message resources into three parts, one for general application stuff, and the other two for specific areas of your application - Sales and Purchasing for example. For the default bundle we don't specify a key and for the other two we'll use salesKey and purchaseKey, as follows...

     <message-resource parameter="myPackage.ApplicationResources" null="false" />
     <message-resource key="salesKey" parameter="myPackage.SalesResources" null="false" />
     <message-resource key="purchaseKey" parameter="myPackage.PurchaseResources" null="false" />

Again you need set up the different properties files for each locale:

6.3 JSP Tag Examples using the Bundle Attribute

Once you've set up multiple bundles, the next question is how do I use alternative bundles? The answer is simply specify the bundle attribute on the Struts JSP Tag.

6.3.1 <html:errors> Examples

     <html:errors />                       <%-- default bundle example --%>
     <html:errors bundle="salesKey"/>      <%-- Sales bundle example --%>
     <html:errors bundle="purchaseKey"/>   <%-- Purchasing bundle example --%>

6.3.2 <html:messages> Examples

    <html:messages id="msg">                      <%-- default bundle example --%>
        <li><bean:write name="msg" /></li>
    </html:messages>

    <html:messages id="msg" bundle="salesKey">    <%-- Sales bundle example --%>
        <li><bean:write name="msg" /></li>
    </html:messages>

    <html:messages id="msg" bundle="purchaseKey"> <%-- Purchasing bundle example --%>
        <li><bean:write name="msg" /></li>
    </html:messages>

6.3.3 <bean:message> Examples

     <bean:message key="some.message.key" />
     <bean:message key="some.message.key" bundle="salesKey" />
     <bean:message key="some.message.key" bundle="purchaseKey" />

6.3.4 <html:text> Example

Most of the form tags (e.g. <html:text> and <html:textarea>) now have a bundle attribute (since Struts Version 1.2.5) which is used in conjunction with attributes such as the titleKey and altKey attributes....

     <html:text property="custNo" 
                titleKey="custNo.label" 
                altKey="custNo.label" 
                bundle="salesKey />

6.4 JSP Tags With the Bundle Attribute

Below is a table of all tags that have the bundle attribute, attributes which are used with the bundle attribute and the version of Struts the bundle attribute was added to that tag (or the Tag was added).

TagAttributes Associated with bundle attribute. Struts Version
bundle added
<bean:message>key1.0
<bean:write>formatKey1.1
 
<html:button>altKey, titleKey1.2.5
<html:cancel>altKey, titleKey1.2.5
<html:checkbox>altKey, titleKey1.2.5
<html:errors>ActionMessages plus header, footer, prefix and suffix attributes1.0
<html:frame>titleKey1.2.5
<html:hidden>altKey, titleKey1.2.5
<html:image>altKey, titleKey, pageKey, srcKey1.0
<html:img>altKey, titleKey, pageKey, srcKey1.0
<html:javascript>ActionMessages1.2.7
<html:link>titleKey1.2.5
<html:messages>ActionMessages plus header and footer attributes1.1
<html:multibox>altKey, titleKey1.2.5
<html:option>key1.0
<html:password>altKey, titleKey1.2.5
<html:radio>altKey, titleKey1.2.5
<html:reset>altKey, titleKey1.2.5
<html:select>altKey, titleKey1.2.5
<html:submit>altKey, titleKey1.2.5
<html:text>altKey, titleKey1.2.5
<html:textarea>altKey, titleKey1.2.5

top

7. Whats in Version 1.2.7?

This section describes changes relating to messages that are in Struts Version 1.2.7. For changes since 1.2.4 see Struts 1.2.7 Release Notes.

Version 1.2.7 Development Release has just been shipped (2005-05-06) and is available here.

7.1 Non Resource Messages

A new resource property has been added to ActionMessage - set to false, to indicate non resource, or in other words its an actual message. So now you don't have to put your error messages in resource bundles - you can just specify them directly in the application.

The easiest way to create one is using the new ActionMessage(String, boolean) constructor in the following way...

        ActionMessage message = new ActionMessage("Customer Number is invalid", false);

So for example in the Action's execute method you might have something like...

        if (<insert-condition-here>) {
            ActionMessages errors = new ActionMessages();
            errors.add("custNo", new ActionMessage("Customer Number is invalid", false));
            saveErrors(request, errors);
        }

This can now also be done in the Validator's validation.xml files as well. There has been a resource attribute specified in the validator dtd for a while - up till now it didn't actually do anything though. Now it does and you can specify error messages there directly, using the resource="false" setting in the following way...

        <field property="custNo" depends="required">
            <msg name="required" key="Customer Number is Missing" resource="false" />
        </field>

top

7.2 Validator Bundle Support

Validator has had minimal support for bundles - you could use the default bundle and thats it. Like resource bundle attributes are already defined in the Validator's dtd - but they just didn't do anything. Well now they do - you can specify them on both the <msg> and <arg> elements as follows...

        <field property="custNo" depends="required">
            <msg name="required" key="custNo.required" bundle="salesKey" />
            <arg key="custNo.label" bundle="purchaseKey" />
        </field>

Below are a couple of points about determining which bundle is used:

A couple of pages have been added to the validator part of the struts-examples webapp showing different bundles in use for both server side validation and JavaScript validation.

top