Search code examples
formsspringspring-mvcpropertyeditordatabinder

Spring MVC custom editor and select-options bad performance


Im using custom editor in Spring MVC to map string valuest to my domain objects. Simple case: User object refers to Company (User.company -> Company). In User form I register data binder:

protected void initBinder(WebDataBinder binder) throws Exception {
    binder.registerCustomEditor(Company.class, new CompanyEditor(appService));
}

Editor is defined as folows:

class CompanyEditor extends PropertyEditorSupport {

    private AppService appService;  

    public CompanyEditor(AppService appService) {
        this.appService = appService;
    }

    public void setAsText(String text) {
        Company company = appService.getCompany(text);
        setValue(company);
    }

    public String getAsText() {
        Company company = (Company) this.getValue();
        if (company != null)
            return company.getId();
        return null;
    }    
}

When I use dropdown in my form

<form:select path="company">
    <form:options items="${companies}" itemLabel="name" itemValue="id"/>
</form:select>

I experience severe performance problems because (to check if company is selected, I suppose) fires setAsText and getAsText for each option, which makes it to run a SQL query for each company.

I thought that setAsText is used when I commit form to make application know how to translate compnany id to Company (persisted) object. Why should it fire it in dropdowns. Any ideas how to fix it?


Solution

  • If your form backing object is stored as session attribute(i.e. you have something like @SessionAttributes("command") in your controller), so you can try to modify your setAsText(String text) method

    public void setAsText(String text) {
            Company currentCompany = (Company) this.getValue();
            if ((currentCompany != null) && (currentCompany.getId().equals(text)))
              return;
    
            Company company = appService.getCompany(text);
            setValue(company);
        }
    

    but I think that Spring 3.1 @Cacheable abstraction was introduced exactly for the such kind of things and is preferable

    see examples in documentation

    @Cacheable("books")
    public Book findBook(ISBN isbn) {...}
    

    P.S. Consider using new Converter SPI instead of Property Editors.

    In general, it's possible to implement a generic converter for your look-up entities, so it will automatically convert entities from text using id if they have some specific attribute, for example, in one of my projects all @Entity types are being automatically converted using a global ConditionalGenericConverter implementation, so I neither register custom property editors during binding nor implement specific converters for types which are simple @Entity classes with @Id annotated primary keys.

    Also it's very convenient when Spring automatically converts textual object ids to the actual entities when they are specified as @RequestParam annotated controller method arguments.