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?
@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.
ResponseEntity represents an HTTP response, including headers, body, and status. While @ResponseBody puts the return value into the body of the response, ResponseEntity also allows us to add headers and status code.
By using @RequestBody annotation you will get your values mapped with the model you created in your system for handling any specific call. While by using @ResponseBody you can send anything back to the place from where the request was generated. Both things will be mapped easily without writing any custom parser etc.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With