Monday, June 26, 2006

Spring MVC Forms

Some notes about Spring MVC and forms. In simple situations when the HTML forms maps well onto the domain model validation can be performed directly on the domain model and the domain model can be used as the command class. This reduces the ammount of code that needs to be written and also means that validators can be used across multiple controllers. The problem is that this only works so long as the form maps well to the existing model. In more complicated situations you will need a seperate command class to handle the processing of the form submission and will then want to validate that so that you can easily map errors in validation back to the form fields. If you map the command class onto the domain model and then validate, discovering which errors relate to which parts of the form becomes tricky. The problem is that then you may end up having duplicate validation code for multiple controllers. When mapping a text input box <input type="text" name="number"> you have several options as to how the mapping is performed.
  • Don't attempt any parsing of the field when mapping the field to the command class and leave it as at String. This then means that your controller has to perform the conversion to an integer and generate the apropriate error message. This complicates your controller with code that could be performed better elsewhere.
  • Have it mapped to a primative int. This means that no matter what the input in the form as long as the conversion and validation succeeds you will always get a number back from the command object even is there wasn't one present in the form, and this is the problem, you can't tell when the user left the field empty.
  • Have it mapped to an Integer. This has the advantage that you can now tell if the user left the field blank as you will get back null. You can only do this though if you change to use a custom property editor as the default is to attempt to parse the empty string which fails and raises an error. I do this in my controller: protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {   // Map numbers to Integer but allow them to be empty.   binder.registerCustomEditor(Integer.class, null, new CustomNumberEditor(Integer.class, true)); }
  • If you use property editors to perform your conversion from strings to integers then you will probably also want to change the error messages that are generated when a problem occurs. Have a look at DefaultMessageCodesResolver for the messages to map. As a starting point I have a property: typeMismatch.java.lang.Integer=Cannot convert to a number. which is displayed when the data binder can't convert a string to a number.

No comments: