Announcement Announcement Module
Collapse
No announcement yet.
Failure for ModelAttribute DataBinding on a x-www-form-urlencoded PUT Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Failure for ModelAttribute DataBinding on a x-www-form-urlencoded PUT

    I have discovered an issue with Spring data binding where a real PUT request doesn't bind correctly to a ModelAttribute whereas a hidden one does (ie, POST with parameter _method=put) when using a HiddenHttpMethodFilter in my servlet.

    My controller class is:

    Code:
    @Transactional(readOnly = false)
    @RequestMapping(value = "/group/{id}",method = RequestMethod.PUT)
    public @ResponseBody Group update(@ModelAttribute Group group) {
    	return directoryService.persist(group);
    }
    	
    @ModelAttribute
    public Group setup(@PathVariable String id) {
    	return StringUtils.isEmpty(id) ? new Group() : directoryService.get(Group.class, id);
    	}
    When I send an x-www-form-urlencoded POST request with _method=put along with any parameters to modify the group, the values are correctly mapped to the ModelAttribute Group. However, when I send a x-www-form-urlencoded PUT request with the same parameters to modify the group, the group is unchanged showing none of the parameters have been bound to the ModelAttribute object fetched by setup.

    It is my understanding that in HTTP, a PUT is allowed to wrap entities like a POST and should therefore bind data the same as a POST within spring.

    I considered that the HiddenHttpMethodFilter might be the issue and so added PUT as a method that should be wrapped:

    Code:
    	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
    			throws ServletException, IOException {
    
    		String paramValue = request.getParameter(this.methodParam);
    		if (("POST".equals(request.getMethod()) || "PUT".equals(request.getMethod())) && StringUtils.hasLength(paramValue)) {
    			String method = paramValue.toUpperCase(Locale.ENGLISH);
    			HttpServletRequest wrapper = new HttpMethodRequestWrapper(method, request);
    			filterChain.doFilter(wrapper, response);
    		}
    ...
    but the appears to make no difference and instead points to an issue with the way data is bound for POSTs vs PUTs deeper within spring.

    Has anyone:
    1) experienced this before,
    2) has a solution, or
    3) has an explanation for why this is happening?

    Cheers,
    Luke

  • #2
    I noticed that my modification to the HiddenHttpMethodFilter wasn't correct as I didn't actually set the method correctly on the wrapper.

    Code:
    		String paramValue = request.getParameter(this.methodParam);
    		if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
    			String method = paramValue.toUpperCase(Locale.ENGLISH);
    			HttpServletRequest wrapper = new HttpMethodRequestWrapper(method, request);
    			filterChain.doFilter(wrapper, response);
    		} else if ("PUT".equals(request.getMethod())){
    			HttpServletRequest wrapper = new HttpMethodRequestWrapper("PUT", request);
    			filterChain.doFilter(wrapper, response);
    		} else {
    			filterChain.doFilter(request, response);
    		}
    However even with this fix, the original request is still a PUT not a POST and the binding still doesn't happen.

    Comment


    • #3
      Binding on RESTful PUT

      Hello all,

      I have the exact same problem. Spring should provide the behavior of binding to an @ModelAttribute for a PUT request as it does for POST, without needing the extra gymnastics of filters and hidden parameters! I was surprised it does not provide this out of the box.

      This is standard REST, and I should be able to send a PUT request to update my form data.

      Zeron

      Comment

      Working...
      X