Stefan Kendall
Stefan Kendall

Reputation: 67802

Using @RequestBody and @ModelAttribute together?

I'm trying to get at the body of a POST, and I'd like the parameters of my method to bind to an object.

Is this possible?

My current declaration doesn't ever get hit:

 @RequestMapping(method = RequestMethod.POST)
public void doStuff(@RequestBody byte[] bodyData, @ModelAttribute Form form, Model model ) {

Looks like I'm getting this exception:

- 2011-02-25 16:57:30,354 - ERROR - http-8080-3 - org.springframework.web.portle
t.DispatcherPortlet - Could not complete request
java.lang.UnsupportedOperationException: @RequestBody not supported

Upvotes: 6

Views: 8901

Answers (2)

Tomek Matynia
Tomek Matynia

Reputation: 11

Unfortunately that is kind of impossible. If you are using portlet version of Spring MVC (and it looks like from the logs) then you might be interested in this JIRA issue.

AnnotationMethodHandlerAdapter uses PortletHandlerMethodInvoker internally and the second is a inner subclass of HandlerMethodInvoker - the place where you can configure HttpMessageConverter-s. But they're set to null. And the property is final.

That even would be to workaround if you could substitute HandlerMethodInvoker, but you can not.. it's constructor-created ;)

One thing to notice is that Servlet version of Spring MVC fully supports HttpMessageConverter-s and does not suffer this issue.

Upvotes: 1

three-cups
three-cups

Reputation: 4385

For this to work correctly, you have to be sure you're using AnnotationMethodHandlerAdapter. This overrides HandlerMethodInvoker's createHttpInputMessage (which is throwing the exception you're seeing). (It does this in a private class.)

I believe you can just include the following in your *-servlet.xml

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>

WARNING: The below answer is for the case of needing @RequestBody and @RequestParam in the same handler method. It does not answer this question, but could be of use to someone.

I've tested this out using Spring 3.0.1. This is possible, but it's somewhat precarious. You MUST have your @RequestBody method argument before your @RequestParam argument. I'm guessing this is because HandlerMethodInvoker reads the request body (along with the GET parameters) when retrieving parameters (and the request body can only be read once).

Here's an example (WARNING: I code in Scala, so I've not compiled this Java code)

@RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(
        @RequestBody String body,
        @RequestParam("param1") String parma1,
        Map<Object, Object> model: Map[AnyRef, AnyRef])
{
    model.put("test", test)
    model.put("body", body)

    return "Layout"
}

An alternative is to use @PathVariable. I've confirmed that this works.

Upvotes: 7

Related Questions