Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC controller with multiple @RequestBody

I was wondering if for example a SpringMVC controller can have a method signature such as

@RequestMapping(value = "/target", method = RequestMethod.POST)
@ResponseBody
public void acceptObject(@RequestBody MyObjectDto dto,@RequestBody String messageBody) {
    //Authenticate messageBody
    //Process mapped DTO
}

The intention was that JSON would be posted to this controller, the raw message body would be authenticated for integrity, and if correct, the JSON would be mapped to a DTO that could be handed off for processing.

At the moment I end up with

java.io.IOException: Stream closed
like image 293
Billy Ross Avatar asked Sep 09 '13 02:09

Billy Ross


1 Answers

Spring uses an interface called HandlerMethodArgumentResolver to decide which arguments it will pass to your handler methods. For parameters annotated with @RequestBody it uses a class called RequestResponseBodyMethodProcessor. This class basically looks in a set of HttpMessageConverter objects for one that can read the content-type of the request and can convert to the specified type. If it finds one, it passes the body of the HttpServletRequest as an InputStream to the HttpMessageConverter object.

In this case, you will probably find some JSON deserializer doing work. It very likely (seeing the IOException you get) consuming the stream and then closing it.

So really this way to do things isn't directly possible.

One solution is to make a Filter that wraps the HttpServletRequest in your own implementation that buffers the InputStream to make it reusable/re-readable as many times as are required. But again the rules for deserializing from the body might be assumed by Spring and not be what you want exactly. In this case you can create your own Annotation and HandlerMethodArgumentResolver which you then register with the application in your configuration. You can then control exactly how things are deserialized from the request body.

Another solution is to combine both MyObjectDto and messageBody into one DTO, if that makes sense to your data model (and to the Spring deserialization process).

like image 76
Sotirios Delimanolis Avatar answered Oct 23 '22 22:10

Sotirios Delimanolis