Customize form:errors output on Spring-MVC

Rylee Brooks

Baa.. took a lot of searching in code, and I don’t particularly like the result – but it is what it is. The main issue is that my designer wanted us to get clever with how form validation error messages are displayed to the user. the <form:errors> tag is very useful for most cases – where you basically only want to display the errors to the users, perhaps with a specific class in mind. You can also ask it to change its default rendering of a <span> element to, say, a <div> element – but my designer wanted something else completely, and sent me on a wild goose chase.


This is what we wanted to achieve:

Error message display

Cheeky error message


The HTML for this is along the lines of:

<img src="images/warning.png" width="31" height="32" 
   class="error_tooltip" title="Name must be between 2 and 150 characters." />
..
..
<!-- Additionally, there's a jquery.ui.tooltip involved... 
     which uses the title to create the nice tooltip when you 
     hover on the image -->

Now, with <form:errors> tag, there’s only so much you can do
(disclaimer: maybe I should have said there’s only so much I can do). If, for example, you want your validation errors to look like the following:

Bland error message

Out of the box error span tag


then all you have to do is use the “out-of-the-box” implementation in your (presumably) jsp view:

<label>Organisation name</label>
<form:input path="name" id="org_name"/>
<form:errors path="name"/>

The snippet above is part of a form. When the form is submitted – it goes through the controller code – something like:

@RequestMapping(value="/create",method=RequestMethodPOST)
public String saveOrganisation(@Valid Organisation org, BindingResult bindingResult) {
  if (bindingResult.hasErrors()) {
    return "org/create"; 
  } else {
    org = organisationService.save(org);
    return "redirect:/org/view/" + org.getId();
  }
}

//The method below is so that you have the complete picture. When a user clicks on 
//the link to create an organisation - a GET request is fired, and the controller
//creates a new organisation entity and returns the create view.
@RequestMapping(value="/create",method=RequestMethod.GET) 
public String createOrganisation(Model model) {
  Organisation o = new Organisation();
  model.addAttribute(o);
  model.addAttribute("title","Create new organisation");
  return "org/create";
}

The saveOrganisation method declares it needs a valid Organisation object – using @Valid. I will write about it in a later part of the MVC tutorial series, but for now it is enough to take it that the validation failed, and the errors are stored in the BindingResult object.
Since the validation fails, the view gets re-rendered, but now it has the errors inside the BindingResult object. When the view gets re-rendered, the <form:errors> tag finds an error on the path supplied to it, and displays the error message inside a <span> element:

<span id="name.errors">Name must be between 2 and 150 characters.</span>

How does this happen? It happens because of the tag used to render the errors: This is org.springframework.web.servlet.tags.form.ErrorsTag (which you can find inside the spring-mvc-3.1.0.RELEASE.jar)

@Override
protected void renderDefaultContent(TagWriter tagWriter) throws JspException {
  tagWriter.startTag(getElement());
  writeDefaultAttributes(tagWriter);
  String delimiter = ObjectUtils.getDisplayString(evaluate("delimiter", getDelimiter()));
  String[] errorMessages = getBindStatus().getErrorMessages();
  for (int i = 0; i < errorMessages.length; i++) {
    String errorMessage = errorMessages[i];
    if (i > 0) {
      tagWriter.appendValue(delimiter);
    }
    tagWriter.appendValue(getDisplayString(errorMessage));
  }
  tagWriter.endTag();
}

So you see – there’s not much you can do there. startTag creates an open tag for you, and allows you to add attributes to it – but then it just iterates over the error messages and writes them out, closing the tag eventually. While you can override the default <span> tag for display by using the element attribute on the <form:errors> tag – whichever way you look at it – you are going to have an HTML tag, with the messages inside it.
Not what I needed at all (which was the message inside the title attribute of an image…)
After a lot of GTE (Google, trial & error) – I came up with the following solution. It is a bit quick and dirty, and there might be a better solution out there (I mean, at the minimum – this can be worked into a tag) – but it’s good enough for a Proof of Concept, and it works:

<!-- instead of <form:errors path="name"> -->
<spring:bind path="name">
  <c:if test="${status.error}">
    <img src="<c:url value="/resources/images/warning.png"/>" 
       width="31" height="32" class="error_tooltip" title="${status.errorMessage}" />
  </c:if>
</spring:bind>
  • Line 2: Bind to the name property of the form – this lets me access its status (via the BindingResult.
  • Line 3: Use the status to test whether there is an error associated with the property.
  • Line 5: When the test above evaluates to true – the status.errorMessage will hold the message text – which I use as the title attribute of the image. That’s it – exactly what I needed:
<img src="/resources/images/warning.png" width="31" height="32" 
   class="error_tooltip" title="Name must be between 2 and 150 characters." />

And that’s it. From here on – it is the tooltip jquery plugin‘s job to pick this up and add the tooltip when the image is hovered.

5 thoughts on “Customize form:errors output on Spring-MVC

  1. Ben Thurley

    Perfect! I too was finding the default form tags a bit limiting. I’m trying to combine spring mvc with twitter bootstrap. Using this I think I can create my own custom tags to create a bootstrap style form but with spring form binding.

    Well written article too. Easy to follow.

  2. Duck Ranger Post author

    @Ben thanks – seems like TB is everywhere nowadays. I use it in my newest project too, so will probably blog about some issues in the next few months. Cheers!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>