Announcement Announcement Module
Collapse
No announcement yet.
Turning off parameter mapping in read-only HTTP requests Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Turning off parameter mapping in read-only HTTP requests

    Hi,

    I'm starting to play around with SpringMVC and I was trying to figure out what would be the best approach to link my entities to the web views as stateless as possible.

    One way I've found is to use the @ModelAttribute on a method that receive in parameter (from the request) the entity ID, which finds it from the service/persistence layer, and return it so it is inserted into the Model of the current request.

    In addition, Spring MVC binds any incoming parameter that matches a field of my entity and updates its value automatically (through the WebDataBinder object).

    My question is concerning this last behaviour. I find it useful that my entity gets updated when some data has been posted by the client. But I would like to avoid it on a simple GET request (which I see as read-only). Current behaviour would allow to update the entity by adding parameter in the query of such request, which could be a security issue.

    I know about the dataBinder.setAllowedFields() and stuff but I would prefer a way to disable any kind of field mapping a any GET request. Is there any way to do it?

    Here's a sample prototype to make it clearer what I am looking for...

    Code:
        @ModelAttribute Entity retrieveEntity(@RequestParam(required=true) Long id) {
        	// This is called before the request handler and before parameters are mapped to the entity
        	return entityRepository.get(id);
        }
        
        @RequestMapping(value="/modify", method=RequestMethod.POST) 
        public ModelAndView handleModifyRequest(@ModelAttribute Entity entity) {
        	// Here, I want my entity to reflect the parameters passed in the posted form (this works)
        	....
        }
        
        @RequestMapping(value="/read", method=RequestMethod.GET) 
        public ModelAndView handleReadRequest(@ModelAttribute Entity entity) {
        	// Here, I DON'T want my entity to reflect the parameters passed in the URL (which is what happens...)
        	....
        }
    Thanks!

  • #2
    You already mentioned your solution, use InitBinder... If you read the documentation you will notice you can use (almost) the same method arguments in the initbinder method as in normal request handling method. Simply detect the GET request and disable binding (by disallowing all fields for instance).

    Comment


    • #3
      Originally posted by Marten Deinum View Post
      You already mentioned your solution, use InitBinder... If you read the documentation you will notice you can use (almost) the same method arguments in the initbinder method as in normal request handling method. Simply detect the GET request and disable binding (by disallowing all fields for instance).
      Yes, but I was wondering if it was possible to disable the binding other than field by field, which is not really efficient for maintenance (if you modify the entity, you have to remember to adjust the field strings properly in one or more controllers...). Kind of "binder.skip()" thing. Seems not.

      Finally, I decided to go with something like this, since it seems that the parameter mapping happen only if the request handler method takes a ModelAttribute parameter

      Code:
      @ModelAttribute Entity retrieveEntity(@RequestParam(required=true) Long id) {
          return entityRepository.get(id);
      }
      
      @RequestMapping(value="/modify", method=RequestMethod.POST) 
      public ModelAndView handleModifyRequest(@ModelAttribute Entity entity) {
          // Here, the request parameters have been mapped to the entity
          ....
      }
      
      @RequestMapping(value="/read", method=RequestMethod.GET) 
      public ModelAndView handleReadRequest(ModelMap model) {
          // This will avoid any parameter mapping to the entity
          Entity entity = (Entity)model.get("entity");
          ....
      }
      Any better solution is welcome! Thanks,
      Baril

      Comment


      • #4
        I strongly suggest a read of the documentation of the DataBinder... You don't have to specify fieldnames, it can also take a wildcard.. So something like this would work..


        Code:
        if (request.getMethod().equals("GET") {
          binder.setDisallowedFields("*"); // Dissallow binding
        }

        Comment


        • #5
          Exactly what I was looking for! Tested and works, thanks!

          Comment

          Working...
          X