views:

83

answers:

1

I'm familiar with how to return json from my @Controller methods using the @ResponseBody annotation.

Now I'm trying to read some json arguments into my controller, but haven't had luck so far. Here's my controller's signature:

@RequestMapping(value = "/ajax/search/sync")
public ModelAndView sync(@RequestParam("json") @RequestBody SearchRequest json) {

But when I try to invoke this method, spring complains that: Failed to convert value of type 'java.lang.String' to required type 'com.foo.SearchRequest'

Removing the @RequestBody annotation doesn't seem to make a difference.

Manually parsing the json works, so Jackson must be in the classpath:

// This works
@RequestMapping(value = "/ajax/search/sync")
public ModelAndView sync(@RequestParam("json") String json) {
    SearchRequest request;
    try {
        request = objectMapper.readValue(json, SearchRequest.class);
    } catch (IOException e) {
        throw new IllegalArgumentException("Couldn't parse json into a search request", e);
    }

Any ideas? Am I trying to do something that's not supported?

+4  A: 

Your parameter should either be a @RequestParam, or a @RequestBody, not both.

@RequestBody is for use with POST and PUT requests, where the body of the request is what you want to parse. @RequestParam is for named parameters, either on the URL or as a multipart form submission.

So you need to decide which one you need. Do you really have a your JSON as a request parameter? This isn't normally how AJAX works, it's normally sent as the request body.

Try removing the @RequestParam and see if that works. If not, and you really are posting the JSON as a request parameter, then Spring won't help you process that without additional plumbing (see Customizing WebDataBinder initialization).

skaffman
+1, You beat me to this. However, one more thing is to make sure that the client set the request `Content-Type` to `application/json`? Try that with `@RequestBody`, and remove `@RequestParam`, as skaffman suggested originally.
Adeel Ansari
Just now I removed the `@RequestBody` annotation and sent the parameter as a GET parameter: `http://localhost:8080/my-app/ajax/search/sync?json={"foo"%3A"bar"}` but I'm getting the same error.
oksayt
@oksayt: As I said, if you want to use `@RequestParam` for parsing JSON, you're going to have to customize your data binding, as described in the link.
skaffman
Ah I see. Now I removed `@RequestParam`, added back `@RequestBody`, and now I'm sending the parameter as a form POST (so the POST body is the json string prefixed with `json=`). But I'm still getting the same error.
oksayt
@oksayt: You don't need the `json=`, it's redundant. You just need the JSON text in the body. oh, and you'll also need `<mvc:annotation-driven/>` for Jackson support (see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-annotation-driven)
skaffman
Thanks for the follow up answers. I verified that I have the `<mvc:annotation-driven/>` directive. To generate a POST like you described, I used TamperData to set the POST data of my request to just the url-encoded json string. This time I didn't get the error and my controller method got invoked, but the parameter object was null.
oksayt
Even though I didn't get it working yet, marking this as correct as it definitely points out the original problem correctly. Thanks!
oksayt