Spring Framework
  1. Spring Framework
  2. SPR-6437

@MVC should provide an "onBind" hook prior to automatic validation

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 3.0 RC2
    • Fix Version/s: 3.1 M2
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      When using @Valid to drive automatic validation of a model object, it is currently not possible to modify the bound model object prior to validation.

      With the SimpleFormController hierarchy it was straightforward to override BaseCommandController's onBind() or onBindAndValidate() methods to achieve custom binding; however, with @MVC it is currently not possible. Neither the WebBindingInitializer API nor an @InitBinder method provides a mechanism to plug in custom binding.

      Note that this was not an issue prior to support for @Valid, since without @Valid developers were responsible for executing validation code within a handler method.

      One possible solution would be to add support for an @PostBinding method or @PreValidation method (or similar) which would be allowed to modify the model after binding but prior to executing the handler method.

        Issue Links

          Activity

          Hide
          Sam Brannen added a comment -

          The following is a description of a use case that requires this functionality.

          • model object contains a list of Foo
          • HTML view uses JavaScript to allow the user to dynamically add new Foos to the list
          • the user accidentally creates extra, empty Foos or deletes all values from an existing Foo in the list
          • business case requires that such empty Foos not be persisted and therefore be deleted from the list
          • the configured Validator, triggered via @Valid, automatically registers errors for required fields in empty Foos
          • removing the empty Foos after validation has occurred is not a solution, because the errors are already present in the BindingResult

          A solution to this problem would be to add custom binding logic that removes empty Foos prior to execution of the Validator, but there is currently no hook in @MVC for plugging in such custom binding logic.

          Show
          Sam Brannen added a comment - The following is a description of a use case that requires this functionality. model object contains a list of Foo HTML view uses JavaScript to allow the user to dynamically add new Foos to the list the user accidentally creates extra, empty Foos or deletes all values from an existing Foo in the list business case requires that such empty Foos not be persisted and therefore be deleted from the list the configured Validator, triggered via @Valid, automatically registers errors for required fields in empty Foos removing the empty Foos after validation has occurred is not a solution, because the errors are already present in the BindingResult A solution to this problem would be to add custom binding logic that removes empty Foos prior to execution of the Validator, but there is currently no hook in @MVC for plugging in such custom binding logic.
          Hide
          Sam Brannen added a comment -

          The following technique suggested by Dave Syer could serve as a possible work-around in the interim.

          In an @InitBinder method, you can call

          binder.setValidator(new DelegatingValidatorAdaptor(binder.getValidator()))
          

          DelegatingValidatorAdaptor could then effectively modify the model before delegating to the real validator.

          Show
          Sam Brannen added a comment - The following technique suggested by Dave Syer could serve as a possible work-around in the interim. In an @InitBinder method, you can call binder.setValidator( new DelegatingValidatorAdaptor(binder.getValidator())) DelegatingValidatorAdaptor could then effectively modify the model before delegating to the real validator.
          Hide
          Dave Syer added a comment -

          Since the binder is responsible for validation, I actually prefer my "workaround" to an additional method-level annotation. Maybe if DataBinder were to pick up a preValidate() method it would be nicer. And we should allow @InitBinder to return a modified binder:

          @InitBinder
          public DataBinder initBinder(WebDataBinder binder) {
              return new SpecialBinder(binder);
          }
          
          Show
          Dave Syer added a comment - Since the binder is responsible for validation, I actually prefer my "workaround" to an additional method-level annotation. Maybe if DataBinder were to pick up a preValidate() method it would be nicer. And we should allow @InitBinder to return a modified binder: @InitBinder public DataBinder initBinder(WebDataBinder binder) { return new SpecialBinder(binder); }
          Hide
          Sam Brannen added a comment -

          I would like to point out that the easiest work-around is simply to avoid using @Valid to trigger validation. You can then modify the model as you wish before manually invoking a validator (as you would in Spring 2.5 anyway).

          Show
          Sam Brannen added a comment - I would like to point out that the easiest work-around is simply to avoid using @Valid to trigger validation. You can then modify the model as you wish before manually invoking a validator (as you would in Spring 2.5 anyway).
          Hide
          Rossen Stoyanchev added a comment - - edited

          Closing this issue due to the identified approach with invoking a validator directly.

          I should also mention that the ModelAttributeMethodProcessor used with the new RequestMappingHandlerAdapter provides hooks around data binding and validation. This may be a suitable option for cross-cutting concerns that apply to all controllers.

          Show
          Rossen Stoyanchev added a comment - - edited Closing this issue due to the identified approach with invoking a validator directly. I should also mention that the ModelAttributeMethodProcessor used with the new RequestMappingHandlerAdapter provides hooks around data binding and validation. This may be a suitable option for cross-cutting concerns that apply to all controllers.

            People

            • Assignee:
              Rossen Stoyanchev
              Reporter:
              Sam Brannen
              Last updater:
              Trevor Marshall
            • Votes:
              6 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                2 years, 46 weeks ago