Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How exactly works @RequestBody annotation and how it is related to the HttpMessageConverter interface?

I am studying how Spring handle REST web services and I have some doubts related to the concept of the HttpMessageConverter.

On the official documentation I can read:

Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.

So the HttpMessageConverter seems to be an interface but what exactly is a strategy interface? Is something related to the strategy pattern or not?

So from what I have understand Spring automatically provide some implementations registered by default when using @EnableWebMvc or

But what exactly does these implementation? Can you provide me a practical example?

I think that it works in this way:

For example a client perform an HttpRequest putting in the body of this request a JSON message (I am not so practical but I think that I can do something like this), then the controller that handle this HttpRequst use an implementation of HttpMessageConverter to convert this JSON message into a model object. I think that it is true also the vice versa.

Is my reasoning correct or am I missing something?

Another doubt is related to the @RequestBody annotation (that I think it is related to the previous topic).

I have this example:

@RequestMapping(value="/orders/{id}", method=RequestMethod.PUT)
@ResponseStatus(HttpStatus.NO_CONTENT) // 204
public void updateOrder(@RequestBody Order updatedOrder, @PathVariable("id") long id) {
    // process updated order data and return empty response
    orderManager.updateOrder(id, updatedOrder);
}

So I think that @RequestBody Order updatedOrder take the value of the updatedOrder input parameter from the body of the HttpRequest and then convert it with into an Order object using an implementation of HttpMessageConverter.

Is it right or am I missing something? If it is right how can chose the right converter?

For example here I found another example similiar to the previous one: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html

@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
    // implementation omitted
}

I think that here it is explicitly specified that it have to use a JSON to MODEL OBJECT converter. Why in the previous example is not specified? How can chose the right converter?

Tnx

like image 983
AndreaNobili Avatar asked Apr 08 '15 14:04

AndreaNobili


People also ask

What is the purpose of @RequestBody annotation?

Simply put, the @RequestBody annotation maps the HttpRequest body to a transfer or domain object, enabling automatic deserialization of the inbound HttpRequest body onto a Java object. Spring automatically deserializes the JSON into a Java type, assuming an appropriate one is specified.

What is @RequestBody annotation in Spring?

The @RequestBody annotation allows us to retrieve the request's body. We can then return it as a String or deserialize it into a Plain Old Java Object (POJO). Spring has built-in mechanisms for deserializing JSON and XML objects into POJOs, which makes this task a lot easier as well.

What is @RequestBody and @ResponseBody annotation in Spring?

@RequestBody and @ResponseBody annotations are used to bind the HTTP request/response body with a domain object in method parameter or return type. Behind the scenes, these annotation uses HTTP Message converters to convert the body of HTTP request/response to domain objects.

What is @RequestBody in REST API?

The request body is used to send and receive data via the REST API. If we are using POST/PUT API, then based on the REST API contract, we should send the whole resource information because these methods work on the whole resource.


1 Answers

Handler method parameters are generated by Spring's HandlerMethodArgumentResolver and handler method return values are processed by Spring's HandlerMethodReturnValueHandler. The implementation that deals with both @ResponseBody and @RequestBody is RequestResponseBodyMethodProcessor.

One of these is registered by default (@EnableWebMvc configuration) with a default list of HttpMessageConverter instances. This is done in WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List). You can find the source code and see which ones are added and in what order.

When Spring goes to generate an argument for a @RequestBody parameter, it loops through the HttpMessageConverter instances, checks if that instance HttpMessageConverter#canRead the content type given in the request and can generate an instance of the parameter type. If it can, Spring will use that HttpMessageConverter to produce an argument. If it can't, Spring will skip it and try the next instance, until it runs out. At which point, it will throw an exception.

For @ResponseBody, the process is the same except Spring now uses HttpMessageConverter#canWrite. It will check if the HttpMessageConverter can serialize the return type and generate response content that fits the content type that is expected in the response (given in the Accept request header).

The consumes attribute of @RequestParam

@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")

has nothing to do with the strategy declared above. The only thing that consumes does here is to restrict the mapping of the handler. For example, take these two handlers

@RequestMapping(value = "/pets", method = RequestMethod.POST)

@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")

The first one can handle any request to /pets with any content type. The second can only handle those requests to /pets with the content type application/json.

like image 118
Sotirios Delimanolis Avatar answered Oct 27 '22 09:10

Sotirios Delimanolis