Posts Tagged: spring framework


7
Sep 09

Grails multi-control property editor implementation

Data binding using current frameworks, Spring, Grails, etc… usually provide a way to marshal/unmarshal input control data into data types. The frameworks usually transparently handle the most common datatypes and allow you to configure/implement others. That process is pretty straightforward and in many cases trivial. When using Spring MVC, for example, one would extend java.beans.PropertyEditorSupport and implement the setAsText and maybe getAsText methods.

I think this handles a large portion of data bindings in web applications, but there wasn’t (at least in frameworks I worked with), a straightforward/reusable way of binding multiple html fields to one data type. I’ve always either had to roll my own custom solution and/or rely on a command (transfer) objects to have a one to one representation of form fields, which I would then bind to the domain object inside a controller action. Some use cases can really benefit from command objects and its decoupling from the domain, but I try to bind directly to domain objects as much as I can, reducing the amount of noise that transfer objects generate. Another solution which I’ve personally never implemented because I thought it was too ugly and leaked too much domain binding implementation into the view layer, was to use a hidden field and then format the multi-field controls into a single text value representation during a submit event, though allowing you to still have a one to one binding between the hidden control and the domain object field.

Today I discovered Grails StructuredPropertyEditor, and after figuring out how to implement it, I was on my way to reducing a bunch of binding boilerplate. This solution is not documented, as many other grails related intricacies, though it does seem like a stable/supported API. After digging through the source code, I figured it out and wanted to share it. So here it is…

I have a form which collects date and time information. The date uses a custom datepicker control and the time uses a custom time control. So two controls, that I need to marshal into one DateTime field in my domain class.

We start off by implementing a custom property editor, which extends PropertyEditorSupport and implements a grails specific StructuredPropertyEditor interface. I decided to use an excellent DateTime implementation class which comes with Joda Time library to store the date/time information. You can easily use any other type of your liking, including the java.lang.Date class.

  public class DateTimePropertyEditor extends PropertyEditorSupport implements StructuredPropertyEditor {

    DateTimeFormatter dateTimeFormat;

    public DateTimePropertyEditor(String format) {
      this.dateTimeFormat = DateTimeFormat.forPattern(format);
    }

    public List getRequiredFields() {
      List requiredFields = new ArrayList();
      requiredFields.add("date");
      return requiredFields;
    }

    public List getOptionalFields() {
      List optionalFields = new ArrayList();
      optionalFields.add("time");
      return optionalFields;
    }

    public Object assemble(Class type, Map fieldValues) throws IllegalArgumentException {
      if (!fieldValues.containsKey("date")) {
        throw new IllegalArgumentException("Can't populate a date without a year");
      }

      String date = (String) fieldValues.get("date");

      try {
        if (StringUtils.isBlank(date)) {
          throw new IllegalArgumentException("Can't populate date/time without a date");
        }
        String time = (String) fieldValues.get("time");
        if (StringUtils.isBlank(time)) time = "00:00 AM";
        String dateTime = date + " " + time;

        return dateTimeFormat.parseDateTime(dateTime);
      }
      catch (Exception nfe) {
        throw new IllegalArgumentException("Unable to parse structured DateTime from request for date.");
      }
    }

  }

Now that we have the property editor defined, we should create a registrar to register it with the application.

  public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

      public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(DateTime.class, new DateTimePropertyEditor("MM/dd/yyyy hh:mm a"));
      }
  }

Now that we have both the property editor and its registrar, we have to declare the registrar bean in the spring beans resources file /grails-app/conf/spring/resources.groovy

  beans = {
    propertyEditorRegistrar(CustomPropertyEditorRegistrar)

    // .... other beans ....
  }

That’s it, we’re done. The only thing left to do is actually create the html controls. There are a few conventions that must be followed in order for the StructuredPropertyEditor to grab the right fields.

  1. You must have a hidden field that’s there pretty much to declare the name of the field you’re binding to and also to state that it’s a ‘struct’ field, which means it’s a structured control made up of various other controls.
  2. The second rule, is that the names of the sub-fields that you are using in StructuredPropertyEditor, in our case ‘date’ and ‘time’, have to be prepended with the field name. So if the field name is ‘myField’, the sub-fields would be prepended with ‘myField_’. In our case, the html inputs should be named ‘myField_date’ and ‘myField_time’.

Here is a GSP snippet…

  <g:hiddenField name="startTime" value="struct" />
  <g:textField name="startTime_date"/>
  <g:textField name="startTime_time"/>

Notice how the field we’re binding is ‘startTime’ and the sub-fields that make up the whole, are ‘startTime_date’ and ‘startTime_time’ linked to ‘date’ and ‘time’ fields used in the assembly of the final field.

Now, all you have to do in the controller, is bind as you usually would, in my case…

bindData(domainObj, params)

That’s it, quick and simple and you have reusable marshaling of multi-control data types.