HTML Select lists in Spring MVC 2.5 with annotations

In this article, I’d like to talk about the use of HTML select lists with Spring MVC since I’ve had to do some development in this area recently and found little documentation available. Select lists are also known as drop-down lists or combo boxes.

In this post I will use an example web application developed using Spring and Spring MVC 2.5. It uses hard-coded data instead of a database to keep things simple. You can download the source code for it here.

Running the example

To run the example, you will need to install Maven. I used version 2.0.9 to write this post. Once you have installed Maven and downloaded and unzipped the source code you can run the application by executing the following in the directory to which you unzipped the source code:

mvn jetty:run

Once Jetty starts up, you have to go to http://localhost:9080/test-webapp/ to view the web application.

The domain model

The application is a simple web app that allows a user to add, remove and edit Users. Each User is a member of a Department. When you add or edit a user, you must specify the Department that they are in – using a Select list. The User and Department classes are in the com.tsl.springmvc.bom package contained within the /src/main/java folder. They make use of two superclasses – IdentifiableType and NamedType (which extends IdentifiableType), two classes which provide id and name fields respectively to subclasses.

The web pages

When you first run the application, you see the list of users page, which is blank. Click on the link in the “create user” link to create a new user and fill in the information, including the Department. Click save. You should now see a new user in the list of users. Edit this user and save it. The original user should have been changed too. Simple, right? Well, it is, once you know how to do it with Spring MVC! Here comes the explanation….

The basic controller code

The UserController class is the Spring MVC controller that manages all operations to do with users. Note that I am using the annotations available in Spring 2.5 instead of the XML configuration. The controller has create, info (to view), save and delete methods which allow the user to perform the relevant operations on Users. It uses UserDao and DepartmentDao to manipulate User and Department objects. All of this is pretty standard Spring MVC 2.5 so I’m not going to enter into much detail here. The basic code is shown below.

@Controller
public class UserController {
    ...
    @Autowired
    private UserDao userService;
 
    @Autowired
    private DepartmentDao departmentDao;
 
    @RequestMapping(value="/user/create.html")
    public ModelAndView create() {
        return new ModelAndView(FORM_VIEW_KEY, FORM_MODEL_KEY, new User());
    }
 
 
    @RequestMapping(value="/user/info.html")
    public ModelAndView info(@RequestParam("id") Integer id) {
        User result = userService.findById(id);
        return new ModelAndView(FORM_VIEW_KEY, FORM_MODEL_KEY, result);
    }
 
    @RequestMapping(value="/user/save.html", method = RequestMethod.POST)
    public ModelAndView save(@ModelAttribute(FORM_MODEL_KEY) User user, BindingResult result, SessionStatus status) {
 
        new UserValidator().validate(user, result);
        if (result.hasErrors())
        {
          return new ModelAndView(FORM_VIEW_KEY, FORM_MODEL_KEY, user);
        }
        else
        {
        	userService.merge(user);
            return new ModelAndView(REDIRECT_SEARCH_VIEW_KEY, search());
        }    	
    }
 
    @RequestMapping(value="/user/delete.html")
    public ModelAndView delete(@RequestParam("id") Integer id) {
        User user = userService.findById(id);
        userService.remove(user);
        return new ModelAndView(REDIRECT_SEARCH_VIEW_KEY, search());
    }
 
    @RequestMapping(value="/user/search.html")
    public ModelMap search() {
        return new ModelMap(SEARCH_MODEL_KEY, 
                userService.findAll());
    }
}

Showing the select list

To show a list of Departments on the create/edit user page, we have to get them using a DAO. This is best done in the controller using the following code:

    @ModelAttribute("departments")
        public Collection<Department> populateDepartments() {
        return departmentDao.findAll();
    }

Note the user of the @ModelAttribute annotation to declare that this is something we will put in the model under the name “departments” so that it can be used on the JSP page. The relevant JSP code (from /src/main/webapp/WEB-INF/jsp/user/user.jsp) to display the list is shown below.

<div class="form-row">
   <label for="department"><fmt:message key="user.form.department"/>:</label>
   <span class="input"><form:select path="department" items="${departments}" itemLabel="name" /></span>
   <form:errors path="department" cssClass="error"/>
</div>

Note the use of ${departments} to indicate that we want to use the model attribute “departments” which we registered with the model using the @ModelAttribute controller annotation.

What you put in the <form:select> element is very important. The code above specifies:

  • Which attribute of the model the select list refers to (the department attribute of a User)
  • Where the list of items for the select comes from (the “departments” model attribute)
  • Which attribute of each select item (in this case department) to show in the list. Here I specify the “name” attribute of the department

Spring MVC allows you to specify an itemValue attribute for the <form:select> element. DO NOT SPECIFY this attribute if you want to use Property Editors (recommended – see below for more information).

Property Editors

When someone chooses the Department that a user belongs to, we want to update the “department” attribute of the User object. We don’t want to have to do some kind of lookup on a department ID or, worse, store the department ID on the user.

What we need to do therefore, is register some kind of converter that is capable of converting a Department to an ID which can be associated with a value in a <form:select> list and, once submitted, doing the reverse conversion on a supplied ID to obtain the original Department object. In JSF, an object that performs this conversion is called a Converter. Spring uses the Java convention and calls it a Property Editor.

The DepartmentEditor is shown below.

public class DepartmentEditor extends PropertyEditorSupport {
 
    private final DepartmentDao departmentDao;
 
    public DepartmentEditor(DepartmentDao departmentDao) {
        this.departmentDao = departmentDao;
    }
 
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        setValue(departmentDao.findById(Integer.parseInt(text)));
    }
 
    @Override
    public String getAsText() {
        Department s = (Department) getValue();
        if (s == null) {
            return null;
        } else {
            return s.getId().toString();
        }
    }
}

The basic convention for implementing a PropertyEditor is:

  1. extend the standard Java class PropertyEditorSupport to make life easier
  2. override the setAsText(String text) method and in the body, call setValue() with the object that corresponds to the text as arguments
  3. override the getAsText() method and in the body, returning a string that represents the object that you obtain when you call getValue()

In DepartmentEditor, I pass a DepartmentDao implementation in the constructor so I can use it to do this conversion.

Registering the Property Editor

You have to associate a Property Editor with the class that it is capable of converting. There are various ways to do this but I find the easiest way (for early experiments anyway) is to register it in the controller using the @InitBinder annotation. Below is the code used to register DepartmentEditor with the UserController. Note that I pass in the Department DAO implementation in the constructor.

    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.registerCustomEditor(com.tsl.springmvc.bom.Department.class, new DepartmentEditor(departmentDao));
    }

On a real project, you’d register property editors in the Spring XML configuration.

Common problems

If you get a ClassCastException such as “java.lang.Integer cannot be cast to com.tsl.springmvc.bom.NamedType”, in my experience it means you’ve specified an itemValue attribute on the form:select list but you’re using PropertyEditors. For example:

<form:select path="department" items="${departments}" itemLabel="name" itemValue="id" />

The problem here (as I understand it) is that there is a conflict between the PropertyEditor (which treats select values as Java objects e.g. Department) and the code for the select which is not working with Objects but their IDs instead. Remove the itemValue attribute and Spring MVC will use the PropertyEditor to generate a string ID for each Department in the Select list and make it compatible with PropertyEditor used when the form is submitted.

If you get a “Failed to convert property” exception e.g.

“Failed to convert property value of type to required type [com.tsl.springmvc.bom.Department] for property department; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type to required type [com.tsl.springmvc.bom.Department] for property department: no matching editors or conversion strategy found”

it means you’ve not completely specified the PropertyEditor. You need to implement the methods I mention in the PropertyEditor section above and register the PropertyEditor correctly with the controller (as I show above) or with Spring in a config file.

Conclusion

Hopefully this article will help other people overcome the problems that I faced when writing select lists using Spring MVC. It’s really simple once you know how!

23 Comments on “HTML Select lists in Spring MVC 2.5 with annotations”

  1. #1 McBain
    on Apr 30th, 2009 at 10:48 am

    Your article should be added to spring documentation. Nice work!

  2. #2 Kevin McCormack
    on Apr 30th, 2009 at 10:52 am

    @McBain – thanks a lot. If anyone knows any appropriate places from which to link to this post (e.g. Spring documentation, forums etc.), please go ahead and do so.

  3. #3 Binh Nguyen Thanh
    on Jun 20th, 2009 at 5:09 am

    Thanks. I love this article.

  4. #4 Eswar
    on Jun 29th, 2009 at 7:54 pm

    Very nice tutorial.

  5. #5 ray
    on Aug 15th, 2009 at 7:09 am

    Thanks a lot. this is very helpful for me.

  6. #6 raja
    on Aug 18th, 2009 at 7:38 pm

    excellent.

  7. #7 shahzad
    on Aug 27th, 2009 at 8:32 am

    i already knew how to do this but still enjoyed the article :)

    good work!!!

  8. #8 julien
    on Sep 10th, 2009 at 5:00 am

    The binding works properly, however, the current element is not selected in the HTML select. Am I missing something?

    Great article!

  9. #9 Matthias
    on Jan 5th, 2010 at 10:38 pm

    Excactly what I’m looking for. Thank you! best regards from Switzerland.

  10. #10 Andre
    on Jan 8th, 2010 at 2:53 am

    This was immensely helpful. You should write a book.

  11. #11 Ben
    on Feb 23rd, 2010 at 3:00 pm

    The thing I had trouble with was completely outside Spring MVC: Without an equals(Object) method on my entity pojos (to use your example, e.g. User) the “selected” attribute would never get added to the relevant option tag, and thus the correct entry would never be selected in the form.

    So, add an equals(Object) method to your entities, and Spring will properly select the right item from your list in the form.

  12. #12 guderin
    on Feb 23rd, 2010 at 10:37 pm

    @Ben! You’re my GOD. Exactly today I had the same problem.
    I spent many hours to solve it and then I came across your comment here. This is it! Thank you very much! Always remember about equals() and hashCode() methods in your entities!

  13. #13 oa
    on Feb 26th, 2010 at 1:44 pm

    Thanks for the tutorial. Exactly what i needed :)

  14. #14 Meendar
    on Apr 30th, 2010 at 12:29 pm

    Thanks for this great tutorial. I am not exactly searching for populating select, but i need a good tutorial to start sping MVC and finally i found one. Thanks again

  15. #15 Chris
    on Jun 18th, 2010 at 5:20 pm

    That’s a great article! Congratulations!
    … but I still have a question :
    how can I manage multiselect lists?

    I have two lists in my domain : weights and selectedWeights.
    These lists have general objects (id, description)
    using the above methodology, debuger shows me that the objects are not of type GeneralObject, but of type GeneralObject@1a66251 or GeneralObject@a31981 etc

    The binding is

  16. #16 Chris
    on Jun 18th, 2010 at 5:22 pm

    sorry for multiple submit, it doesnt show the html code

    form:select path=”model.weights” items=”${model.weights}” itemLabel=”description”

  17. #17 Ken
    on Jul 1st, 2010 at 5:09 pm

    Thanks for this!! I searched for hours looking for this and only found it after I learned the right words to use to describe it. It should be inserted somewhere into the Spring Framework Reference manual, in the section that talks about editors as an example of how to use editors.

  18. #18 Caden
    on Aug 24th, 2010 at 4:02 pm

    Superb!!! Flawless, simple, to the point and, it works!!

    Thank you!!

  19. #19 ady
    on Oct 13th, 2010 at 12:00 pm

    Excellent explanation! Thank you!

  20. #20 Phil
    on Dec 14th, 2010 at 10:45 pm

    Fantastic!

    I’m currently experiencing the “ClassCastException” issue you mentioned, but I’m using a different approach. To take your example, I want a drop-down list of all Departments, plus an additional item in the list, “All Departments”, that should set my entity’s department property to null. Do you have an idea how to do this? I’ve registered a custom PropertyEditor for the bean’s property path and requiredType, but I still receive the error. Here’s what I’m doing so far (the “allDepartments” var is a list of Department beans):

    <form:select path=”department”>
    <option value=”"><All Departments></option>
    <c:forEach items=”${allDepartments}” var=”d”>
    <form:option value=”${”}${d.id}”>${d.shortDescription}</form:option>
    </c:forEach>
    </form:select>

  21. #21 Enez
    on Feb 14th, 2011 at 4:14 pm

    Hi, can enybody redirect me to som example with filtering select with pagination and is that possible?

  22. #22 Megha
    on Aug 16th, 2012 at 12:31 pm

    Thanks a ton..i dont know how much pages i surfed to find the annotation based example ..great work..this link should come at first place in search

  23. #23 Johnny
    on Dec 12th, 2012 at 1:06 am

    Thanks a lot, mate. Good job.
    Help a lot. the Spring official manual is so brief

Leave a Comment