springspring-mvcspring-3spring-4spring-mvc-initbinders

Configure two @InitBinder to work with the same Model or Entity but for different @RequestMappings


I have a controller where works fine, It can register and update an entity, just how the following about to create the forms to save and update an entity respectively

@RequestMapping(value="/registrar.htm", method=RequestMethod.GET)
public String crearRegistrarFormulario(Model model){
   …
}

@RequestMapping(value="/{id}/actualizar.htm", method=RequestMethod.GET)
public String crearActualizarFormulario(@PathVariable("id") String id, Model model){
  …
}

Until here I have no problems.

My problem is about the @InitBinder

I need work with the same entity Deportista (Sportsman), one special setting for save and update. For example

@InitBinder
public void registrarInitBinder(WebDataBinder binder) { // register or save
    logger.info(">>>>>>>> registrarInitBinder >>>>>>>>>>>>>");
    …
    CustomDateEditor customDateEditor = new CustomDateEditor(...
    … 
}

@InitBinder
public void actualizarInitBinder(WebDataBinder binder) { // update
    logger.info(">>>>>>>> actualizarInitBinder >>>>>>>>>>>>>");
    …
    CustomDateEditor customDateEditor = new CustomDateEditor(...
    …
    binder.setDisallowedFields(…) //I need this only for update
}

I have read the following:

The links mentioned work around different entities, for example User and Customer, it through the @InitBinder's value attribute, but I need work with the same entity, how I can configure the @InitBinder's value to indicate Spring use or discriminate each @InitBinder? one for save and update respectively.

Thanks

Edit: From the Serge Ballesta's answer, the following is mandatory too:

@Controller
@RequestMapping(value="/deportista")
@SessionAttributes(value={"deportistaRegistrar", "deportistaActualizar"})
public class DeportistaController {
…

@RequestMapping(value="/registrar.htm", method=RequestMethod.GET)
public String crearRegistrarFormulario(Model model){
    Deportista deportista = new Deportista();
    model.addAttribute("deportistaRegistrar", deportista);
    return "deportista.formulario.registro";
}

@RequestMapping(value="/{id}/actualizar.htm", method=RequestMethod.GET)
public String crearActualizarFormulario(@PathVariable("id") String id, Model model){
    Deportista deportista = this.fakeMultipleRepository.findDeportista(id);
    model.addAttribute("deportistaActualizar", deportista);
    return "deportista.formulario.actualizacion";
}   

It to let work his answer:

// registrarInitBinder will be used here
@RequestMapping(value="/registrar.htm", method=RequestMethod.POST)
public String doCrearRegistrarFormulario(@ModelAttribute("deportistaRegistrar") XXX value,
    BindingResult result, Model model){
   …
}

// actualizarInitBinder will be used here
@RequestMapping(value="/{id}/actualizar.htm", method=RequestMethod.POST)
public String crearActualizarFormulario(@PathVariable("id") String id,
    @ModelAttribute("deportistaActualizar") XXX value, BindingResult result, Model model){
  …
}

Solution

  • According to the javadoc page for @InitBinder, you can use multiple init-binders in one single controllers, and specialize them with the name of the model attribute variable for which they will be applied. Example :

    @InitBinder("saveValue")
    public void registrarInitBinder(WebDataBinder binder) { // register or save
        logger.info(">>>>>>>> registrarInitBinder >>>>>>>>>>>>>");
        …
        CustomDateEditor customDateEditor = new CustomDateEditor(...
        … 
    }
    
    @InitBinder("updateValue")
    public void actualizarInitBinder(WebDataBinder binder) { // update
        logger.info(">>>>>>>> actualizarInitBinder >>>>>>>>>>>>>");
        …
        CustomDateEditor customDateEditor = new CustomDateEditor(...
        …
        binder.setDisallowedFields(…) //I need this only for update
    }
    

    and then (XXX is the type of the form object that will be processed by the submit)

    // registrarInitBinder will be used here
    @RequestMapping(value="/registrar.htm", method=RequestMethod.POST)
    public String doCrearRegistrarFormulario(@ModelAttribute("saveValue") XXX value,
        BindingResult result, Model model){
       …
    }
    
    // actualizarInitBinder will be used here
    @RequestMapping(value="/{id}/actualizar.htm", method=RequestMethod.POST)
    public String crearActualizarFormulario(@PathVariable("id") String id,
        @ModelAttribute("updateValue") XXX value, BindingResult result, Model model){
      …
    }