Struts 1.2 & Velocity Tools; ActionMessagesTool and ErrorsTool confusion
This is probably obvious to most experienced front end programmers. But since I spent 30 minutes digging in apache code, and 15 minutes fixing a misunderstanding in my code, I'll blogg my embarrassment.
Let's say you have a struts action with the following catch clause. Notice that we use the ActionMessages class instead of the ActionErrors class to contain error messages. The use of ActionErrors and ActionError is one of the things that have changed from Struts version 1.1 and 1.2 (See also previous blog entry)
catch (SomebusinessException e) {
ActionMessages errors = new ActionMessages();
errors.add("name", new ActionMessage("error.general.name_already_in_use"));
saveErrors(request, errors);
return mapping.findForward("input_error");
}
This might lead you to think that you should use the ActionMessages Tool in Velocity. This is (of course) not the case since we still use the "saveErrors" method in our Action subclass. So, when rendering the error message you (still) have to include the ErrorsTool in your toolbox.xml
<tool>
<key>errors</key>
<scope>request</scope>
<class>
org.apache.velocity.tools.struts.ErrorsTool
</class>
</tool>
The ActionMessagesTool should NOT be used. ErrorsTool and ActionMessagesTool, and both are actually just very thin wrappers to the StrutsUtils class. The ActionMessagesTool class uses a method in StrutsUtils called getMessages() that does the following ;
ActionMessages errors =
(ActionMessages)request.getAttribute(Globals.MESSAGE_KEY);
The ErrorsTool uses a method in the StrutsUtils class called getErrors() that does the following ;
ActionMessages errors =
(ActionMessages)request.getAttribute(Globals.ERRORS_KEY);
So using the wrong Velocity tool (ActionMessagesTool) gives you an empty collection of messages when you have invoked the saveErrors method in your Action class. Beware!