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

Manuel Jordan picture Manuel Jordan · Sep 16, 2014 · Viewed 11.7k times · Source

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){
  …
}

Answer

Serge Ballesta picture Serge Ballesta · Sep 16, 2014

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){
  …
}