Spring's RestTemplate is a robust, popular Java-based REST client. The Spring for Android RestTemplate Module provides a version of RestTemplate that works in an Android environment.
The RestTemplate
class is the heart of the Spring for Android RestTemplate library. It is conceptually similar to other template classes found in other Spring portfolio projects. RestTemplate's behavior is customized by providing callback methods and configuring the HttpMessageConverter
used to marshal objects into the HTTP request body and to unmarshal any response back into an object. When you create a new RestTemplate
instance, the constructor sets up several supporting objects that make up the RestTemplate functionality.
Here is an overview of the functionality supported within RestTemplate
.
RestTemplate
provides an abstraction for making RESTful HTTP requests, and internally, RestTemplate
utilizes a native Android HTTP client library for those requests. There are two native HTTP clients available on Android, the standard J2SE facilities, and the HttpComponents HttpClient. The standard JS2SE facilities are made available through the SimpleClientHttpRequestFactory
, while the HttpClient is made available through the HttpComponentsClientHttpRequestFactory
. The default ClientHttpRequestFactory
used when you create a new RestTemplate
instance differs based on the version of Android on which your application is running.
Google recommends to use the J2SE facilities on Gingerbread (Version 2.3) and newer, while previous versions should use the HttpComponents HttpClient. Based on this recommendation RestTemplate
checks the version of Android on which your app is running and uses the appropriate ClientHttpRequestFactory
. To utilize a specific ClientHttpRequestFactory
you must either pass a new instance into the RestTemplate
constructor, or call setRequestFactory(ClientHttpRequestFactory requestFactory)
on an existing RestTemplate
instance.
RestTemplate
supports sending and receiving data encoded with gzip compression. The HTTP specification allows for additional values in the Accept-Encoding
header field, however RestTemplate
only supports gzip compression at this time.
Object to JSON marshaling in Spring for Android RestTemplate requires the use of a third party JSON mapping library. There are two libraries supported in Spring for Android, Jackson JSON Processor, and Google Gson. While Jackson is a well known JSON parsing library, the Gson library is smaller, which would result in an smaller Android app when packaged.
Object to XML marshaling in Spring for Android RestTemplate requires the use of a third party XML mapping library. The Simple XML serializer is used to provide this marshaling functionality.
RSS and Atom feed support in Spring for Android RestTemplate requires the use of a third party feed reader library. The Android ROME Feed Reader is used to provide this functionality.
RestTemplate
provides higher level methods that correspond to each of the six main HTTP methods. These methods make it easy to invoke many RESTful services and enforce REST best practices.
The names of RestTemplate
methods follow a naming convention, the first part indicates what HTTP method is being invoked and the second part indicates what is returned. For example, the method getForObject()
will perform a GET, convert the HTTP response into an object type of your choice and return that object. The method postForLocation()
will do a POST, converting the given object into a HTTP request and return the response HTTP Location header where the newly created object can be found. In case of an exception processing the HTTP request, an exception of the type RestClientException
will be thrown. This behavior can be changed by plugging in another ResponseErrorHandler
implementation into the RestTemplate.
For more information on RestTemplate
and it's associated methods, please refer to the API Javadoc
public void delete(String url, Object... urlVariables) throws RestClientException; public void delete(String url, Map<String, ?> urlVariables) throws RestClientException; public void delete(URI url) throws RestClientException;
public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException; public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException; public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException; public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables); public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables); public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
public HttpHeaders headForHeaders(String url, Object... urlVariables) throws RestClientException; public HttpHeaders headForHeaders(String url, Map<String, ?> urlVariables) throws RestClientException; public HttpHeaders headForHeaders(URI url) throws RestClientException;
public Set<HttpMethod> optionsForAllow(String url, Object... urlVariables) throws RestClientException; public Set<HttpMethod> optionsForAllow(String url, Map<String, ?> urlVariables) throws RestClientException; public Set<HttpMethod> optionsForAllow(URI url) throws RestClientException;
public URI postForLocation(String url, Object request, Object... urlVariables) throws RestClientException; public URI postForLocation(String url, Object request, Map<String, ?> urlVariables); public URI postForLocation(URI url, Object request) throws RestClientException; public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables); public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables); public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException; public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables); public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;
public void put(String url, Object request, Object... urlVariables) throws RestClientException; public void put(String url, Object request, Map<String, ?> urlVariables) throws RestClientException; public void put(String url, Object request, Map<String, ?> urlVariables) throws RestClientException;
Objects passed to and returned from the methods getForObject()
, getForEntity()
, postForLocation()
, postForObject()
and put()
are converted to HTTP requests and from HTTP responses by HttpMessageConverter
instances. Converters for the main mime types are registered by default, but you can also write your own converter and register it via the messageConverters()
property.
The default converter instances registered with the template are ByteArrayHttpMessageConverter
, StringHttpMessageConverter
, and ResourceHttpMessageConverter
. If you are app is running on Android 2.2 or later, then XmlAwareFormHttpMessageConverter
and SourceHttpMessageConverter
are registered, as these two message converters require the javax.xml.transform
library. On Android 2.1, this falls back to the FormHttpMessageConverter
which lacks some of the XML support in the other two.
The HttpMessageConverter
interface is shown below to give you a better feel for its functionality.
public interface HttpMessageConverter<T> { // Indicates whether the given class can be read by this converter. boolean canRead(Class<?> clazz, MediaType mediaType); // Indicates whether the given class can be written by this converter. boolean canWrite(Class<?> clazz, MediaType mediaType); // Return the list of {@link MediaType} objects supported by this converter. List<MediaType> getSupportedMediaTypes(); // Read an object of the given type form the given input message, and returns it. T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; // Write an given object to the given output message. void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }
Concrete implementations for the main media (mime) types are provided in the framework and are registered by default within RestTemplate
The following HttpMessageConverter
implementations are available in Spring for Android. For all converters a default media type is used but can be overridden by calling the setSupportedMediaTypes()
method.
An HttpMessageConverter
implementation that can read and write Strings from the HTTP request and response. By default, this converter supports all text media types (text/*
), and writes with a Content-Type
of text/plain
.
An HttpMessageConverter
implementation that can read and write form data from the HTTP request and response. By default, this converter reads and writes the media type application/x-www-form-urlencoded
. Form data is read from and written into a MultiValueMap<String, String>
.
An HttpMessageConverter
implementation that can read and write byte arrays from the HTTP request and response. By default, this converter supports all media types (*/*
), and writes with a Content-Type
of application/octet-stream
. This can be overridden by setting the supportedMediaTypes property, and overriding getContentType(byte[])
.
An HttpMessageConverter
implementation that can read and write XML from the HTTP request and response using Simple Framework's Serializer
. XML mapping can be customized as needed through the use of Simple's provided annotations. When additional control is needed, a custom Serializer
can be injected through the Serializer
property. By default, this converter reads and writes the media types application/xml
, text/xml
, and application/*+xml
.
It is important to note that this is not a Spring OXM compatible message converter. It is a standalone implementation that enables XML serialization through Spring for Android.
An HttpMessageConverter
implementation that can read and write JSON using Jackson JSON Processor's ObjectMapper
. JSON mapping can be customized as needed through the use of Jackson's provided annotations. When further control is needed, a custom ObjectMapper
can be injected through the ObjectMapper
property for cases where custom JSON serializers/deserializers need to be provided for specific types. By default this converter supports (application/json
).
An HttpMessageConverter
implementation that can read and write JSON using Google Gson's Gson
class. JSON mapping can be customized as needed through the use of Gson's provided annotations. When further control is needed, a custom Gson
can be injected through the Gson
property for cases where custom JSON serializers/deserializers need to be provided for specific types. By default this converter supports (application/json
).
Please note that this message converter and the MappingJacksonHttpMessageConverter
support application/json
. Because of this, only one will automatically be loaded with a new RestTemplate
instance. If you include Jackson and Gson in your classpath, Jackson will take precedence over Gson.
An HttpMessageConverter
implementation that can read and write javax.xml.transform.Source
from the HTTP request and response. Only DOMSource
, SAXSource
, and StreamSource
are supported. By default, this converter supports (text/xml
) and (application/xml
).
An HttpMessageConverter
implementation that can read and write RSS and Atom feeds from the HTTP request and response using Android ROME Feed Reader. The data is read from and written into a com.google.code.rome.android.repackaged.com.sun.syndication.feed.synd.SyndFeed
. By default, this converter supports (application/rss+xml
) and (application/atom+xml
).
An HttpMessageConverter
implementation that can read and write RSS feeds from the HTTP request and response. The data is read from and written into a com.google.code.rome.android.repackaged.com.sun.syndication.feed.rss.Channel
. By default, this converter supports (application/rss+xml
).
Because the SyndFeedHttpMessageConverter
provides a higher level of abstraction around RSS and Atom feeds, the RssChannelHttpMessageConverter
is not automatically added when you create a new RestTemplate
instance. If you prefer to use this message converter then you have to manually add it to the RestTemplate
instance.
An HttpMessageConverter
implementation that can read and write Atom feeds from the HTTP request and response. The data is read from and written into a com.google.code.rome.android.repackaged.com.sun.syndication.feed.atom.Feed
. By default, this converter supports (application/atom+xml
).
Because the SyndFeedHttpMessageConverter
provides a higher level of abstraction around RSS and Atom feeds, the AtomFeedHttpMessageConverter
is not automatically added when you create a new RestTemplate
instance. If you prefer to use this message converter then you have to manually add it to the RestTemplate
instance.
Add the spring-android-rest-template artifact to your classpath:
<dependency> <groupId>org.springframework.android</groupId> <artifactId>spring-android-rest-template</artifactId> <version>${spring-android-version}</version> </dependency> <dependency> <groupId>org.springframework.android</groupId> <artifactId>spring-android-core</artifactId> <version>${spring-android-version}</version> </dependency>
Google's provided Android toolset does not include dependency management support. However, through the use of third party tools, you can use Maven to manage dependencies and build your Android app. See the Spring for Android and Maven section for more information.
Spring for Android RestTemplate supports several optional libraries. These optional libraries are used by different HttpMessageConverter
instances within RestTemplate
. If you would like to make use of these message converters, then you need to include the corresponding libraries in your classpath.
Include the following Jackson dependencies to your classpath to enable the MappingJacksonHttpMessageConverter
.
<dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>${jackson-version}</version> </dependency>
<dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>${jackson-version}</version> </dependency>
Add the following Google Gson dependency to your classpath to enable the GsonHttpMessageConverter
.
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>${gson-version}</version> </dependency>
Add the following Simple XML Serializer dependency to your classpath to enable the SimpleXmlHttpMessageConverter
.
<dependency> <groupId>org.simpleframework</groupId> <artifactId>simple-xml</artifactId> <version>${simple-version}</version> </dependency>
Add the following Android ROME Feed Reader dependencies to your classpath to enable the RssChannelHttpMessageConverter
, AtomFeedHttpMessageConverter
, and SyndFeedHttpMessageConverter
. This library depends on a forked version of JDOM to work on Android 2.1 and earlier. The JDOM library addresses a bug in the Android XML parser.
<dependency> <groupId>com.google.code.android-rome-feed-reader</groupId> <artifactId>android-rome-feed-reader</artifactId> <version>${android-rome-version}</version> </dependency>
<dependency> <groupId>org.jdom</groupId> <artifactId>jdom</artifactId> <version>${jdom-fork-version}</version> </dependency>
The Android ROME Feed Reader is not available through the Maven central repository. When using Maven, you will need to include the following repository in your POM.
<!-- For developing with Android ROME Feed Reader --> <repository> <id>android-rome-feed-reader-repository</id> <name>Android ROME Feed Reader Repository</name> <url>https://android-rome-feed-reader.googlecode.com/svn/maven2/releases</url> </repository>
Using RestTemplate
, it's easy to invoke RESTful APIs. Below are several usage examples that illustrate the different methods for making RESTful requests.
All of the following examples are based on a sample Android application. You can retrieve the source code for the sample app with the following command:
$ git clone git://github.com/SpringSource/spring-android-samples.git
The following example shows a query to google for the search term "SpringSource".
RestTemplate restTemplate = new RestTemplate(); String url = "https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={query}"; String result = restTemplate.getForObject(url, String.class, "SpringSource");
Gzip compression can significantly reduce the size of the response data being returned in a REST request. Gzip must be supported by the web server to which the request is being made. By setting the content coding type of the Accept-Encoding
header to gzip
, you are requesting that the server respond using gzip compression. If gzip is available, or enabled on the server, then it should return a compressed response. RestTemplate checks the Content-Encoding
header in the response to determine if, in fact, the response is gzip compressed. At this time, RestTemplate only supports the gzip content coding type in the Content-Encoding
header. If the response data is determined to be gzip compressed, then a GZIPInputStream is used to decompress it.
The following example shows how to request a gzip compressed response from the server.
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setAcceptEncoding(ContentCodingType.GZIP); HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders); RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
One thing to note, is that when using the J2SE facilities with the SimpleClientHttpRequestFactory
, Gingerbread and newer automatically set the Accept-Encoding header to request gzip responses. This is built in functionality of newer versions of Android. If you desire to disable gzip, then you must set the identity
value in the header.
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setAcceptEncoding(ContentCodingType.IDENTITY); HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders); RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
Suppose you have defined a Java object you wish to populate from a RESTful web request that returns JSON content.
Define your object based on the JSON data being returned from the RESTful request:
public class Event { private Long id; private String title; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public String setTitle(String title) { this.title = title; } }
Make the REST request:
String url = "http://mypretendservice.com/events"; RestTemplate restTemplate = new RestTemplate(); Event[] events = restTemplate.getForObject(url, Event[].class);
You can also set the Accept
header for the request:
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setAccept(Collections.singletonList(new MediaType("application","json"))); HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders); String url = "http://mypretendservice.com/events"; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<Event[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Event[].class); Event[] events = responseEntity.getBody();
Alternatively, you can use the GsonHttpMessageConverter
for JSON marshaling. The following repeats the same request, utilizing Gson.
HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setAccept(Collections.singletonList(new MediaType("application","json"))); HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders); String url = "http://mypretendservice.com/events"; GsonHttpMessageConverter messageConverter = new GsonHttpMessageConverter(); List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); messageConverters.add(messageConverter); RestTemplate restTemplate = new RestTemplate(); restTemplate.setMessageConverters(messageConverters); ResponseEntity<Event[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Event[].class); Event[] events = responseEntity.getBody();
Using the same Java object we defined earlier, we can modify the requests to retrieve XML.
Define your object based on the XML data being returned from the RESTful request. Note the annotations used by Simple to marshal the object:
@Root public class Event { @Element private Long id; @Element private String title; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public String setTitle(String title) { this.title = title; } }
To marshal an array of events from xml, we need to define a wrapper class for the list:
@Root(name="events") public class EventList { @ElementList(inline=true) private List<Event> events; public List<Event> getEvents() { return events; } public void setEvents(List<Event> events) { this.events = events; } }
Make the REST request:
String url = "http://mypretendservice.com/events"; RestTemplate restTemplate = new RestTemplate(); EventList eventList = restTemplate.getForObject(url, EventList.class);
You can also specify the Accept
header for the request:
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>(); acceptableMediaTypes.add(new MediaType("application","xml")); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setAccept(acceptableMediaTypes); HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders); String url = "http://mypretendservice.com/events"; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<EventList> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, EventList.class); EventList eventList = responseEntity.getBody();
POST a Java object you have defined to a RESTful service that accepts JSON data.
Define your object based on the JSON data expected by the RESTful request:
public class Message { private long id; private String subject; private String text; public void setId(long id) { this.id = id; } public long getId() { return id; } public void setSubject(String subject) { this.subject = subject; } public String getSubject() { return subject; } public void setText(String text) { this.text = text; } public String getText() { return text; } }
Make the REST request. In this example, the request responds with a string value:
Message message = new Message(); message.setId(555); message.setSubject("test subject"); message.setText("test text"); String url = "http://mypretendservice.com/sendmessage"; RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.postForObject(url, message, String.class);
You can also specify the Content-Type
header in your request:
Message message = new Message(); message.setId(555); message.setSubject("test subject"); message.setText("test text"); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(new MediaType("application","json")); HttpEntity<Message> requestEntity = new HttpEntity<Message>(message, requestHeaders); String url = "http://mypretendservice.com/sendmessage"; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); String result = responseEntity.getBody();
The following is a basic example of loading an RSS feed:
String url = "http://mypretendservice.com/rssfeed"; RestTemplate restTemplate = new RestTemplate(); SyndFeed = restTemplate.getForObject(url, SyndFeed.class);
It is possible that you need to adjust the Media Type associated with the SyndFeedHttpMessageConverter
. By default, the converter is associated with application/rss+xml
and application/atom+xml
. An RSS feed might instead have a media type of text/xml
, for example. The following code illustrates how to set the media type.
String url = "http://mypretendservice.com/rssfeed"; SyndFeedHttpMessageConverter converter = new SyndFeedHttpMessageConverter(); List<MediaType> mediaTypes = new ArrayList<MediaType>(); mediaTypes.add(new MediaType("text","xml")); converter.setSupportedMediaTypes(mediaTypes); List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); messageConverters.add(converter); RestTemplate restTemplate = new RestTemplate(); restTemplate.setMessageConverters(messageConverters); SyndFeed feed = restTemplate.getForObject(url, SyndFeed.class);