Rober2D2
Rober2D2

Reputation: 588

Spring MVC 3. How to modify the form after binding but before validation

I am developing an application using Spring MVC 3 annotated style controllers. In some ocassions I need to add/modify some field values depending on session variables or some other condition. To complicate things, the field may have a fixed value if some condition is matched, and read user input if not. The question is: There is a way to modify the form after binding but before validation using spring mvc 3? It was quite simple with SimpleFormController (onBind method), but I can't find a way in spring mvc 3.

An example:

a) I initialize the binder for my form. Add a validator, set the list of allowed fields, and add a list of generic property editors

@InitBinder(value = COMMAND_NAME)
@Override
public void initBinder(final WebDataBinder binder, final HttpServletRequest httpServletRequest) {
    binder.setValidator(reenvioAsientoValidator);
    binder.setAllowedFields(ReenvioAsientoForm.getListaCamposPermitidos());
    .... Add some custom property editors for booleans, integers ....
}

b) Create model object

@ModelAttribute(value = COMMAND_NAME)
public ReenvioAsientoForm rellenaModelo(final HttpServletRequest httpServletRequest) {

    final ReenvioAsientoForm form = new ReenvioAsientoForm();       
    ... Add some field values, which cannot be modified by user ...
    return form;
}

c) Binding happens: And it can modify any field that is in the allowedFields list. Even those I setted in phase b)

d) THIS IS WHAT I CAN'T DO. I need to set/modify some fields of the form. Can't be done in the create model phase, because those fields are in the allowedFields list (Depending on different conditions, they can be readonly or accept user input)

e) Validation happens

f) Controller POST method is invoked

@RequestMapping(value = URI_REENVIO_ASIENTO, method = RequestMethod.POST)
public ModelAndView submit(@Valid @ModelAttribute(COMMAND_NAME) final ReenvioAsientoForm form, final BindingResult result, HttpServletRequest request) {
    .....
}

Somethings I've tried:

  1. Modify inside validator, before validation: That is a possible solution, but I find it nasty, because I am using the validator for something it is not intended. Plus it only works if the form is validated.
  2. Using a CustomPropertyEditor. This way I can check the condition and set the value during binding. The problem is that the binder is fired only if a the property is present in the request. If there were someway to fire it always, it would be a nice solution

Upvotes: 4

Views: 2185

Answers (1)

Tomas Pinos
Tomas Pinos

Reputation: 2862

The easiest workaround is to avoid using @Valid to trigger validation.

@Autowired
Validator validator;

@RequestMapping(value = URI_REENVIO_ASIENTO, method = RequestMethod.POST)
public ModelAndView submit(@ModelAttribute(COMMAND_NAME) final ReenvioAsientoForm form, final BindingResult result, HttpServletRequest request) {
    // here comes the custom logic 
    // that will be executed after binding and before validation

    // trigger validation 
    validator.validate(form, result);

    // handle validation result and return view name
    ...
}

See related issue in Spring JIRA and the explanation that such hook / annotation won't be implemented - @MVC should provide an "onBind" hook prior to automatic validation.

Upvotes: 4

Related Questions