Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-5695

Allow an @ModelAttribute method to be invoked after the @RequestMapping method

    Details

    • Type: New Feature
    • Status: Resolved
    • Priority: Minor
    • Resolution: Won't Fix
    • Affects Version/s: 2.5.6
    • Fix Version/s: None
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      @ModelAttribute is used for common (static) data and is used before the request is passed to the controller.
      It would nice to be able to use the same annotation after the handling process as well, to take care of common request data. The idea is to isolate the common model functionality in a separate method (such as dealing defaults) and leave the controller to focus only on the dynamic behaviour.

      An example of handling the initial request and initializing defaults (if ModelAttribute would be used after) would be:

      @ModelAttribute("bundleList) List<Bundle> bundleList(@ModelAttribute("selection")  SelectionCommand selectionCommand) {
          if (selectionCommand.getDisplayChoice() == null)
               selectionCommand.setDisplayChoice(BundleListingOptions.NAME);
         // display bundles using the display choice...
      }

      In this case, if @ModelAttribute would be used after the controller, the method could inspect the parameters and populate the model map itself (currently this needs to be handled in the controller, i.e.:

      if (selection ...) {
        model.addAttribute("bundleList", listBundles());
      })

      To be backwards compatible, the annotation could have a new parameter added to it (an enum) that can indicate when the binding should occur, before or after the handler invocation.

        Issue Links

          Activity

          Hide
          senoctar Patras Vlad Sebastian added a comment -

          I would like this feature too. Something similar to referenceData of MVC 2. Maybe add another option to the annotation to specify if you want it to be called or not in case of a redirect (because you usually don't), or maybe add some way so it could get the view name.

          Show
          senoctar Patras Vlad Sebastian added a comment - I would like this feature too. Something similar to referenceData of MVC 2. Maybe add another option to the annotation to specify if you want it to be called or not in case of a redirect (because you usually don't), or maybe add some way so it could get the view name.
          Hide
          rstoya05-aop Rossen Stoyanchev added a comment -

          @ModelAttribute is used for common (static) data and is used before the request is passed to the controller.

          Very importantly @ModelAttribute is also used to pre-load a command object (e.g. from the database) so the object is available for data binding when arguments to the @RequestMapping method are resolved. So the ability to invoke a @ModelAttribute method before @RequestMapping methods is quite essential to data binding.

          The idea is to isolate the common model functionality in a separate method (such as dealing defaults) and leave the controller to focus only on the dynamic behaviour.

          In most cases an @ModelAttribute method should not be called after a redirect or after binding and validation errors. That creates more rules and complexity and potentially leads to surprises. I don't think adding flags to @ModelAttribute would solve the problem and those flags wouldn't make sense when @ModelAttribute is used on method arguments.

          Although I see what you're trying to achieve, remember that an @ModelAttribute method supports the same argument types as an @RequestMapping method but only one of its return values (i.e. returning an Object to be added to the model). That means you can declare an @ModelAttribute argument, which can cause data binding or validation errors and all of that would occur after the @RequestMapping method selected a view. You could have no option to change the view since you can only return an Object to be added to the model.

          It would be much simpler in this case to call the separate method from the @RequestMapping method as necessary.

          Show
          rstoya05-aop Rossen Stoyanchev added a comment - @ModelAttribute is used for common (static) data and is used before the request is passed to the controller. Very importantly @ModelAttribute is also used to pre-load a command object (e.g. from the database) so the object is available for data binding when arguments to the @RequestMapping method are resolved. So the ability to invoke a @ModelAttribute method before @RequestMapping methods is quite essential to data binding. The idea is to isolate the common model functionality in a separate method (such as dealing defaults) and leave the controller to focus only on the dynamic behaviour. In most cases an @ModelAttribute method should not be called after a redirect or after binding and validation errors. That creates more rules and complexity and potentially leads to surprises. I don't think adding flags to @ModelAttribute would solve the problem and those flags wouldn't make sense when @ModelAttribute is used on method arguments. Although I see what you're trying to achieve, remember that an @ModelAttribute method supports the same argument types as an @RequestMapping method but only one of its return values (i.e. returning an Object to be added to the model). That means you can declare an @ModelAttribute argument, which can cause data binding or validation errors and all of that would occur after the @RequestMapping method selected a view. You could have no option to change the view since you can only return an Object to be added to the model. It would be much simpler in this case to call the separate method from the @RequestMapping method as necessary.
          Hide
          rstoya05-aop Rossen Stoyanchev added a comment - - edited

          Re-opening after realizing there may be an opportunity to support this as a natural extension of the solution for SPR-6299.

          The trigger for invoking a model attribute method after (and not before) would be a dependency on another model attribute and that is a command object in the @RequestMapping method signature.

          This way there is no need have additional flags or enums on @ModelAttribute. We simply detect that the model attribute you depend on will be available after the @RequestMapping method is invoked.

          This seems to fit the spirit of the [email protected] reference data method and the original description of this ticket.

          Show
          rstoya05-aop Rossen Stoyanchev added a comment - - edited Re-opening after realizing there may be an opportunity to support this as a natural extension of the solution for SPR-6299 . The trigger for invoking a model attribute method after (and not before) would be a dependency on another model attribute and that is a command object in the @RequestMapping method signature. This way there is no need have additional flags or enums on @ModelAttribute. We simply detect that the model attribute you depend on will be available after the @RequestMapping method is invoked. This seems to fit the spirit of the [email protected] reference data method and the original description of this ticket.
          Hide
          rstoya05-aop Rossen Stoyanchev added a comment -

          After implementing SPR-6299 and some further thought (e.g. see here) I am closing this once again.

          Show
          rstoya05-aop Rossen Stoyanchev added a comment - After implementing SPR-6299 and some further thought (e.g. see here ) I am closing this once again.

            People

            • Assignee:
              rstoya05-aop Rossen Stoyanchev
              Reporter:
              costin Costin Leau
              Last updater:
              Rossen Stoyanchev
            • Votes:
              3 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                3 years, 6 weeks, 5 days ago