Post Nested Object to Spring MVC controller using JSON

Update: since Spring 3.1, it’s possible to use @Valid On @RequestBody Controller Method Arguments.

@RequestMapping(value="/ajax/saveVendor.do", method = RequestMethod.POST)
public @ResponseBody AjaxResponse saveVendor( @Valid @RequestBody UIVendor vendor,
                                              BindingResult result,
                                              Locale currentLocale )

After much trial and error, I’ve finally figured out, as well as I can, what the problem is. When using the following controller method signature:

@RequestMapping(value="/ajax/saveVendor.do", method = RequestMethod.POST)
public @ResponseBody AjaxResponse saveVendor( @Valid UIVendor vendor,
                                              BindingResult result,
                                              Locale currentLocale )

The client script has to pass the field in the object in post-data (typically “application/x-www-form-urlencoded”) format (i.e., field=value&field2=value2). This is done in jQuery like this:

$.post( "mycontroller.do", $.param(object), callback, "json" )

This works fine for simple POJO objects that don’t have child objects or collections, but once you introduce significant complexity to the object being passed, the notation used by jQuery to serialize the object data is not recognized by Spring’s mapping logic:

object[0][field]

The way that I solved this problem was to change the method signature in the controller to:

@RequestMapping(value="/ajax/saveVendor.do", method = RequestMethod.POST)
public @ResponseBody AjaxResponse saveVendor( @RequestBody UIVendor vendor,
                                              Locale currentLocale )

And change the call from client to:

    $.ajax(
            {
              url:"ajax/mycontroller.do", 
              type: "POST", 
              data: JSON.stringify( objecdt ), 
              success: callback, 
              dataType: "json",
              contentType: "application/json"
            } );    

This requires the use of the JSON javascript library. It also forces the contentType to “application/json”, which is what Spring expects when using the @RequestBody annotation, and serializes the object to a format that Jackson can deserialize into a valid object structure.

The only side effect is that now I have to handle my own object validation inside of the controller method, but that’s relatively simple:

BindingResult result = new BeanPropertyBindingResult( object, "MyObject" );
Validator validator = new MyObjectValidator();
validator.validate( object, result );

If anyone has any suggestions to improve upon this process, I’m all ears.

Leave a Comment