Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring - binding to an object rather than a String or primitive

Let's say I have the following command object:

class BreakfastSelectCommand{
    List<Breakfast> possibleBreakfasts;
    Breakfast selectedBreakfast;
}

How can I have spring populate "selectedBreakfast" with a breakfast from the list?

I was figuring I'd do something like this in my jsp:

<form:radiobuttons items="${possibleBreakfasts}" path="selectedBreakfast"  />

But this doesn't seem to work. Any ideas?

thanks,

-Morgan

like image 635
morgancodes Avatar asked Feb 05 '09 16:02

morgancodes


1 Answers

The key to it all of this is the PropertyEditor.

You need to define a PropertyEditor for your Breakfast class and then configure the ServletDataBinder using registerCustomEditor in the initBinder method of your controller.

example:

public class BreakfastPropertyEditor extends PropertyEditorSupport{
    public void setAsText(String incomming){
        Breakfast b = yourDao.findById( Integer.parseInt(incomming));
        setValue(b);
    }
    public String getAsText(){
        return ((Breakfast)getValue()).getId();
    }
}

note you'll be needing some null checking etc, but you get the idea. In your controller:

public BreakfastFooBarController extends SimpleFormController {
    @Override
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
        binder.registerCustomEditor(Breakfast.class, new BreakfastPropertyEditor(yourDao));
    }
}

things to watch out for:

  • PropertyEditor's are not thread safe
  • if you need spring beans, either manually inject them or define them in spring as prototype scope and use method injection into your controller
  • throw IllegalArgumentException if the inbound parameter is not valid/not found, spring will convert this into a binding error correctly

hope this helps.

Edit (in response to the comment): It looks a little strange in the given example because BreakfastSelectCommand doesn't look like an entity, I'm not sure what the actual scenario you have is. Say it is an entity, for example like Person with a breakfast property then the formBackingObject() method would load the Person object from the the PersonDao and return it as the command. The binding phase would then change the breakfast property depending on the selected value, such that the command that arrives in onSubmit has the breakfast property all set up.

Depending on the implementation of your DAO objects calling them twice or attempting to load the same entity twice doesn't actually mean that you will get two SQL statements being run. This applies particularly to Hibernate, where it guarantees that it will return the same object that is in it's session for a given identifier, thus running letting the binding attempt to load the Breakfast selection even through it hasn't changed shouldn't result in any undue overhead.

like image 185
Gareth Davis Avatar answered Oct 24 '22 05:10

Gareth Davis