How does the Spring @ResponseBody annotation work?

JavaJsonSpringRestSpring Mvc

Java Problem Overview


I have a method that is annotated in the following way:

/**
* Provide a list of all accounts.
*/
//	TODO 02: Complete this method.  Add annotations to respond
//	to GET /accounts and return a List<Account> to be converted.
//	Save your work and restart the server.  You should get JSON results when accessing 
//	http://localhost:8080/rest-ws/app/accounts
@RequestMapping(value="/orders", method=RequestMethod.GET)
public @ResponseBody List<Account> accountSummary() {
	return accountManager.getAllAccounts();
}

So I know that by this annotation:

@RequestMapping(value="/orders", method=RequestMethod.GET)

this method handle GET HTTP requests made to the resource represented by the URL /orders.

This method calls a DAO object that returns a List.

where Account represents a user on the system and has some fields that represent this user, something like:

public class Account {

	@Id
	@Column(name = "ID")
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Long entityId;

	@Column(name = "NUMBER")
	private String number;

	@Column(name = "NAME")
	private String name;

	@OneToMany(cascade=CascadeType.ALL)
	@JoinColumn(name = "ACCOUNT_ID")
	private Set<Beneficiary> beneficiaries = new HashSet<Beneficiary>();

    ...............................
    ...............................
    ...............................
}

My question is: How exactly the does the @ResponseBody annotation work?

It is situated before the returned List<Account> object so I think that it refers to this List. The course documentation states that this annotation serves the function to:

> ensure that the result will be written to the HTTP response by an HTTP > Message Converter (instead of an MVC View).

And also reading on the official Spring documentation: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

it seems that it takes the List<Account> object and puts it into the Http Response. Is this correct or am I misunderstanding?

Written into the comment of the previous accountSummary() method there is:

> You should get JSON results when accessing > http://localhost:8080/rest-ws/app/accounts

So what exactly does this mean? Does it mean that the List<Account> object returned by the accountSummary() method is automatically converted into JSON format and then put into the Http Response? Or what?

If this assertion is true, where is it specified that the object will be automatically converted into JSON format? Is the standard format adopted when the @ResponseBody annotation is used or is it specified elsewhere?

Java Solutions


Solution 1 - Java

First of all, the annotation doesn't annotate List. It annotates the method, just as RequestMapping does. Your code is equivalent to

@RequestMapping(value="/orders", method=RequestMethod.GET)
@ResponseBody
public List<Account> accountSummary() {
    return accountManager.getAllAccounts();
}

Now what the annotation means is that the returned value of the method will constitute the body of the HTTP response. Of course, an HTTP response can't contain Java objects. So this list of accounts is transformed to a format suitable for REST applications, typically JSON or XML.

The choice of the format depends on the installed message converters, on the values of the produces attribute of the @RequestMapping annotation, and on the content type that the client accepts (that is available in the HTTP request headers). For example, if the request says it accepts XML, but not JSON, and there is a message converter installed that can transform the list to XML, then XML will be returned.

Solution 2 - Java

The first basic thing to understand is the difference in architectures.

One end you have the MVC architecture, which is based on your normal web app, using web pages, and the browser makes a request for a page:

Browser <---> Controller <---> Model
               |      |
               +-View-+

The browser makes a request, the controller (@Controller) gets the model (@Entity), and creates the view (JSP) from the model and the view is returned back to the client. This is the basic web app architecture.

On the other end, you have a RESTful architecture. In this case, there is no View. The Controller only sends back the model (or resource representation, in more RESTful terms). The client can be a JavaScript application, a Java server application, any application in which we expose our REST API to. With this architecture, the client decides what to do with this model. Take for instance Twitter. Twitter as the Web (REST) API, that allows our applications to use its API to get such things as status updates, so that we can use it to put that data in our application. That data will come in some format like JSON.

That being said, when working with Spring MVC, it was first built to handle the basic web application architecture. There are may different method signature flavors that allow a view to be produced from our methods. The method could return a ModelAndView where we explicitly create it, or there are implicit ways where we can return some arbitrary object that gets set into model attributes. But either way, somewhere along the request-response cycle, there will be a view produced.

But when we use @ResponseBody, we are saying that we do not want a view produced. We just want to send the return object as the body, in whatever format we specify. We wouldn't want it to be a serialized Java object (though possible). So yes, it needs to be converted to some other common type (this type is normally dealt with through content negotiation - see link below). Honestly, I don't work much with Spring, though I dabble with it here and there. Normally, I use

@RequestMapping(..., produces = MediaType.APPLICATION_JSON_VALUE)

to set the content type, but maybe JSON is the default. Don't quote me, but if you are getting JSON, and you haven't specified the produces, then maybe it is the default. JSON is not the only format. For instance, the above could easily be sent in XML, but you would need to have the produces to MediaType.APPLICATION_XML_VALUE and I believe you need to configure the HttpMessageConverter for JAXB. As for the JSON MappingJacksonHttpMessageConverter configured, when we have Jackson on the classpath.

I would take some time to learn about Content Negotiation. It's a very important part of REST. It'll help you learn about the different response formats and how to map them to your methods.

Solution 3 - Java

Further to this, the return type is determined by

  1. What the HTTP Request says it wants - in its Accept header. Try looking at the initial request as see what Accept is set to.

  2. What HttpMessageConverters Spring sets up. Spring MVC will setup converters for XML (using JAXB) and JSON if Jackson libraries are on he classpath.

If there is a choice it picks one - in this example, it happens to be JSON.

This is covered in the course notes. Look for the notes on Message Convertors and Content Negotiation.

Solution 4 - Java

@RequestBody annotation binds the HTTPRequest body to the domain object. Spring automatically deserializes incoming HTTP Request to object using HttpMessageConverters. HttpMessageConverter converts body of request to resolve the method argument depending on the content type of the request. Many examples how to use converters https://upcodein.com/search/jc/mg/ResponseBody/page/0

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndreaNobiliView Question on Stackoverflow
Solution 1 - JavaJB NizetView Answer on Stackoverflow
Solution 2 - JavaPaul SamsothaView Answer on Stackoverflow
Solution 3 - JavapaulchapmanView Answer on Stackoverflow
Solution 4 - JavasergeyView Answer on Stackoverflow