In an earlier post we saw how Spring depended on MessageConverters to convert the request stream to java object and also the java objects to appropriate response formats.
As we had defined a Jackson converter, our controller's return objects were converted by the DispatcherServlet to JSON.
Similarly where the method parameters were annotated with Requestbody, DispatcherServlet ensured that the message converter read the request and converted it to the Java object of the parameter's type.
But what if we build a service that must be capable of returning resource in various formats ?
For example I would like my resource to expose both JSON and XML representation of the data. This gives alternatives to the client. But I also need my same resource (or more specifically - same URL) to support these varied formats.
The first step would be to set the message converts needed:
For JSON like before:
The third format I included was ATOM:
Now that we have created the message converters, we need to make the dispatcher servlet aware of the same:
This completes the configuration on the server. Thus adding new data formats to the Resource has minimal code impacts.
Now consider the get call: http://localhost:8080/SampleRest/api/user/1
This will cause server to return the user with id 1. But there remains an important question.
How does the Server know in what format to return the user record?
This is where the accept header comes in. All Requests made must include the expected format in the accept header. Correspondingly all message converts are associated with a particular media type.
For e.g. if we look at the MappingJacksonHttpMessageConverter
Similarly for MarshallingHttpMessageConverter we have "text/xml" and "application/xml".
For AtomFeedHttpMessageConverter it is "application/atom+xml".
We are not tied to using these types only. We can provide our own values if needed:
As we had defined a Jackson converter, our controller's return objects were converted by the DispatcherServlet to JSON.
Similarly where the method parameters were annotated with Requestbody, DispatcherServlet ensured that the message converter read the request and converted it to the Java object of the parameter's type.
But what if we build a service that must be capable of returning resource in various formats ?
For example I would like my resource to expose both JSON and XML representation of the data. This gives alternatives to the client. But I also need my same resource (or more specifically - same URL) to support these varied formats.
The first step would be to set the message converts needed:
For JSON like before:
<bean id="jsonMessageConverter"For XML, Spring provides the MarshallingHttpMessageConverter:
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
<bean id="xmlConverter"The class uses JAXB internally for the marshaling and unmarshaling process. So I had to add a Jaxb2Marshaller:
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller"/>
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">The class is from Spring's oxm jar. (Also make sure to annotate the bound classes with JAXB's XmlRootElement annotation. Else Spring throws a weird 406 error)
<property name="classesToBeBound">
<list>
<value>com.test.controller.User</value>
</list>
</property>
</bean>
The third format I included was ATOM:
<bean id="atomConverter"For Atom to work I also had to add the sun.syndication-1.0.0.jar
class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter"/>
Now that we have created the message converters, we need to make the dispatcher servlet aware of the same:
<beanAs seen here the "messageConverters" property is capable of accepting a list of converters.
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
<ref bean="xmlMessageConverter"/>
<ref bean="atomConverter"/>
</list>
</property>
</bean>
This completes the configuration on the server. Thus adding new data formats to the Resource has minimal code impacts.
Now consider the get call: http://localhost:8080/SampleRest/api/user/1
This will cause server to return the user with id 1. But there remains an important question.
How does the Server know in what format to return the user record?
This is where the accept header comes in. All Requests made must include the expected format in the accept header. Correspondingly all message converts are associated with a particular media type.
For e.g. if we look at the MappingJacksonHttpMessageConverter
public MappingJackson2HttpMessageConverter() {Here the messageConverter will work for media content of type "application/json".
super(new MediaType("application", "json", DEFAULT_CHARSET));
}
Similarly for MarshallingHttpMessageConverter we have "text/xml" and "application/xml".
For AtomFeedHttpMessageConverter it is "application/atom+xml".
We are not tied to using these types only. We can provide our own values if needed:
<bean id="jsonConverter"The client must provide one of these values in its Accept Header. This enables the DispatcherServlet to process the request and generate the response correctly.
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
</bean>