4

I have a spring mvc controller like the following

@RequestMapping(value="/new", method=RequestMethod.POST)
public String createBooking(@Valid Booking booking, BindingResult bindingResult, Model model, Principal principal)
{
    if(bindingResult.hasErrors()) {
        return "booking/edit";
    }
    //Store Booking in db...
    ...

The problem is the Booking object i get from the POST is constructed by Spring, but one of the properties required by the validator cannot be populated, as the property is not present in the form. So my question is is there a way for me to intercept the Booking before it gets processed by the @Valid tag handler to add this required property?

Cheers! NFV

nfvindaloo
  • 948
  • 2
  • 11
  • 24
  • I had problem like yours. May be it will be useful. http://stackoverflow.com/questions/40064924/add-value-into-request-object-before-validation?noredirect=1#comment67477926_40064924 – koa73 Oct 18 '16 at 08:30

2 Answers2

2

There are 2 ways to modify the model attribute object before the @Valid will trigger:

  1. Remove @Valid and autowire the validator and manually trigger the validator:
class MyController {

  private final Validator validator;

  class MyController(Validator validator) {
    this.validator = validator;
  }

  @PostMapping("/new")
  public String createBooking(Booking booking, BindingResult bindingResult, Model model, Principal principal) {
    // edit booking here

    validator.validate(booking, result)

    // original method body here
  }
}

  1. Decorate the default validator and pre-process the booking object inside the decorated validator.
class MyController {

  @InitBinder
  public void initBinder(WebDataBinder binder) {
      binder.setValidator(new PreProcessBookingValidator(binder.getValidator()));
  }

  @PostMapping("/new")
  public String createBooking(@Valid Booking booking, BindingResult bindingResult, Model model, Principal principal) {
    ...
  }

  private static class PreProcessBookingValidator implements Validator {
        private final Validator validator;

        public PreProcessBookingValidator(Validator validator) {
            this.validator = validator;
        }

        @Override
        public boolean supports(@Nonnull Class<?> clazz) {
            return validator.supports(clazz);
        }

        @Override
        public void validate(@Nonnull Object target, @Nonnull Errors errors) {
            if (target instanceof Booking) {
                Booking booking = (Booking) target;
                // manipulate booking here

            }

            validator.validate(target, errors);
        }
    }

}

(This second tip is what I picked up from https://github.com/spring-projects/spring-framework/issues/11103)

Wim Deblauwe
  • 25,113
  • 20
  • 133
  • 211
0

I'm not sure I understand the question, but it sounds like you want to set a field in the command object to a value before your command is bound by the form submission. If so, you can add a method in your controller as follows...

@ModelAttribute
public Booking getBooking() {
    Booking booking = new Booking();
    booking.setMyRequiredProperty("some value");
    return booking;
}

Hope that helps

hyness
  • 4,785
  • 1
  • 22
  • 24
  • This is correct, but I think nfvindaloo wanted to preprocess bean submitted from form before standard validation applies (@Valid). It's easy to apply custom validator, but not a standard one. Maybe this is an answer - http://stackoverflow.com/questions/18049204/possible-to-modify-modelattribute-before-validated-is-run . – Xdg Feb 02 '16 at 13:23
  • No, that is not an answer - @ ModelAttribute on method is executed first and then parameter @ ModelAttribute is executed, bean is populated from form and we're stucked - read this http://stackoverflow.com/questions/25011568/spring-mvc-modelattribute-method . So I have no idea how to preprocess class before @ Valid. – Xdg Feb 02 '16 at 15:32