1

In my Spring 4 driven portlet I have a data-object which contains a date-field. In the JSP-view I have two separate fields for it, date (dd/mm/yyyy) and time (hh/mm). The action handler in my controller receives the form-data by using the @ModelAttribute-annotation:

@ActionMapping(params = "action=update")
public void onUpdate(@Valid @ModelAttribute("myObject") MyObject myObject,
   BindingResult bindingResult, ActionResponse response, SessionStatus status)
{
   if (!bindingResult.hasErrors())
      myObjectService.save(myObject);
   else
      // provide 'myObject' in the view which displays validation errors
}

I need to merge date and time before the form-data is validated an onUpdate() receives myObject, since in MyObject there is only one java.util.Calendar-field for the whole date available.

Idea 1 to work around this need

Now I thought, I could also split the date into two separate fields in MyObject and provide a getter which merges the values on demand:

@Column(name = "begin")
public Calendar getBegin()
{
   // return calendar object built from this.beginDate and this.beginTime
}

but I think this is not a good idea for several reasons (see this question: Hibernate Annotations - Which is better, field or property access?) I want the model-object to be a mirror of the database-record and hence it should be validated before getting assigned.

Idea 2

Another approch would be, to create or modify the calendar-object in myObject on demand, when setting the date or time:

@Column(name = "begin")
@Temporal(TemporalType.TIMESTAMP)
private Calendar begin;

public void setBeginDate(String value)
{
    // assign a new calendar object to "begin", if "begin" is null
    // set only day, month and year components on this calendar object
}

public void setBeginTime(String value)
{
    // see "setBeginDate", do the same with hours and minutes
}

The problem here is, that a new calendar-object is created if only one of the fields "date" or "time" is valid. The field in the view is filled with the current date or current time (depending on which value was correct)

I can even solve this problem, by adding another private isValidDate-flag to the model. But I think this is an unclean solution.

Conclusion

I think there is a big difference between myObject for the controller and myObject as an actual model-object. myObject should be a model-object, as soon as being validated and "mapped".

So here my questions:

  • Do you think that the last point reveals using @ModelAttribute as a bad idea generally?
  • Or is there a way mapping and validating form-data BEFORE the MyObject-instance is created?
  • If not, how would you recommend to solve the problem?
Community
  • 1
  • 1
fishbone
  • 3,140
  • 2
  • 37
  • 50

1 Answers1

0

EDIT : @initBinder is OK the other way around (1 field -> N attributes)

I don't know if the framework can do what you want (N fields -> 1 attribute) out of the box without getting into the binding plumbing.

Here are two simple solutions to get around the issue :

  • Do it the old "Struts" way and create a MyObjectForm object that you will use exclusively in your view, and then transform it in your controller to MyObject. You can still use your @Valid at the service layer MyObjectService which is technically sound.

  • If MyObject does not contain dozens of attributes, Forget about @ModelAttribute + Controller layer validation and just use @RequestParam for each field. Service layer validation is still in play.

You can certainly hack something that will allow you to "bind" your form data to your object manually using Spring MVC's internal facilities, but in the end it will be something like my 2nd point, with much more confusing plumbing.

Michael Técourt
  • 3,457
  • 1
  • 28
  • 45