2. RestTemplate Module

2.1 Introduction

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.

2.2 Overview

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.

2.2.1 HTTP Client

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 SimpleClientHttpRequestFactory, while the HttpClient can be utilized via HttpComponentsAndroidClientHttpRequestFactory. Support for native HttpClient 4.0 is deprecated in favor of the Android port of HttpClient 4.3. 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 Android 2.3 (Gingerbread) 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.

Spring for Android also includes support for third-party HTTP client libraries. HttpClient 4.3 for Android is compatible with all versions of Android, and may be utilized as an alternative to the native clients by simply including the dependency in your project. If Spring for Android detects HttpClient 4.3, then it will automatically configure it as the default ClientHttpRequestFactory. HttpClient 4.3 has a considerable number of bug fixes and improvements over the native HttpClient 4.0 included within Android.

dependencies {
    compile('org.apache.httpcomponents:httpclient-android:$httpClientVersion')
}
			

An additional ClientHttpRequestFactory based on OkHttp is available as an alternative to the two native clients. RestTemplate can be configured to use OkHttpRequestFactory through the RestTemplate constructor or by setting the requestFactory property. It is supported on Android 2.3 (Gingerbread) and newer, however in order to use it, you must include the OkHttp dependency in your project.

dependencies {
    compile('com.squareup.okhttp:okhttp-urlconnection:$okHttpVersion')
}
			

2.2.2 Gzip Compression

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.

2.2.3 Object to JSON Marshaling

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 2.x 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.

2.2.4 Object to XML Marshaling

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.

2.3 How to get

There are a few methods for including external jars in your Android app. You can use Gradle or Maven for dependency management, or manually download them and include them in your app's libs/ folder.

2.3.1 Gradle

Android Studio and the New Build System for Android offer a Gradle plugin for building Android apps. Gradle provides built in dependency management, which can be used to include the Spring for Android dependencies in your project.

Add the spring-android-rest-template dependency to your build.gradle file:

dependencies {
    compile('org.springframework.android:spring-android-rest-template:${version}')
}
			

2.3.2 Maven

Maven can be used to manage dependencies and build your Android app. See the Spring for Android and Maven section for more information. Additional dependencies may be required, depending on which HTTP Message Converters you are using within RestTemplate. See the Message Converters section for more information.

Add the spring-android-rest-template dependency to your pom.xml file:

<dependency>
    <groupId>org.springframework.android</groupId>
    <artifactId>spring-android-rest-template</artifactId>
    <version>${spring-android-version}</version>
</dependency>
			

2.3.3 Ant and Eclipse

In order to use RestTemplate in your Android application, you must include the following Spring for Android jars in the libs/ folder.

  • spring-android-rest-template-{version}.jar
  • spring-android-core-{version}.jar

If you are building your project with Ant, Ant will automatically include any jars located in the libs/ folder located in the root of your project. However, in Eclipse you must manually add the jars to the Build Path. Follow these steps to add the jars to your existing Android project in Eclipse.

  1. Refresh the project in Eclipse so the libs/ folder and jars display in the Package Explorer.
  2. Right-Click (Command-Click) the first jar.
  3. Select the BuildPath submenu.
  4. Select Add to Build Path from the context menu.
  5. Repeat these steps for each jar.

2.4 RestTemplate Constructors

The RestTemplate constructors are listed below. The default constructor includes a standard set of message body converters. For a list of default converters, see the HTTP Message Conversion section.

RestTemplate();

RestTemplate(ClientHttpRequestFactory requestFactory);

RestTemplate(List<HttpMessageConverter<?>> messageConverters);
		

If you would like to specify an alternate ClientHttpRequestFactory, such as OkHttpClientHttpRequestFactory, then you can do so by passing it in to the requestFactory parameter.

OkHttpClientHttpRequestFactory requestFactory = new OkHttpClientHttpRequestFactory();
RestTemplate template = new RestTemplate(ClientHttpRequestFactory requestFactory);
		

2.5 RestTemplate Methods

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

2.5.1 HTTP DELETE

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;
		

2.5.2 HTTP GET

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;
		

2.5.3 HTTP HEAD

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;
		

2.5.4 HTTP OPTIONS

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;
		

2.5.5 HTTP POST

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;
		

2.5.6 HTTP PUT

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;
		

2.6 HTTP Message Conversion

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. 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.

2.6.1 Default Message Converters

The default RestTemplate constructor registers a standard set of message converters for the main mime types. 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, ResourceHttpMessageConverter, SourceHttpMessageConverter and AllEncompassingFormHttpMessageConverter. See the following table for more information.

Table 2.1. Default Message Converters

Message Body ConverterInclusion Rule
ByteArrayHttpMessageConverterAlways included
StringHttpMessageConverter
ResourceHttpMessageConverter
SourceHttpMessageConverter
AllEncompassingFormHttpMessageConverter
SimpleXmlHttpMessageConverterIncluded if the Simple XML serializer is present.
MappingJackson2HttpMessageConverterIncluded if the Jackson 2.x JSON processor is present.
GsonHttpMessageConverterIncluded if Gson is present. Jackson 2.x takes precedence over Gson if both are available on the classpath.

2.6.2 Available Message Converters

The following HttpMessageConverter implementations are available in Spring for Android. For all converters a default media type is used but can be overridden through the supportedMediaTypes property.

ByteArrayHttpMessageConverter

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[]).

FormHttpMessageConverter

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>.

AllEncompassingFormHttpMessageConverter

Extension of FormHttpMessageConverter, adding support for XML and JSON-based parts.

ResourceHttpMessageConverter

An HttpMessageConverter implementation that can read and write Resource Resources. By default, this converter can read all media types. Written resources use application/octet-stream for the Content-Type.

SourceHttpMessageConverter

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.

StringHttpMessageConverter

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.

SimpleXmlHttpMessageConverter

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.

Add the following dependency to your classpath to enable the SimpleXmlHttpMessageConverter.

Gradle:

dependencies {
    compile('org.simpleframework:simple-xml:${version}')
}
			

Maven:

<dependency>
    <groupId>org.simpleframework</groupId>
    <artifactId>simple-xml</artifactId>
    <version>${simple-version}</version>
</dependency>
			

MappingJackson2HttpMessageConverter

An HttpMessageConverter implementation that can read and write JSON using Jackson (2.x)'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.

Please note that this message converter and the GsonHttpMessageConverter both support application/json by default. Because of this, you should only add one JSON message converter to a RestTemplate instance. RestTemplate will use the first converter it finds that matches the specified mime type, so including both could produce unintended results.

Include the following dependencies in your classpath to enable the MappingJackson2HttpMessageConverter. Please note that if you are manually copying the jars into your project, you will also need to include the jackson-annotations and jackson-core jars.

Gradle:

dependencies {
    compile('com.fasterxml.jackson.core:jackson-databind:${version}')
}
			

Maven:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson-version}</version>
</dependency>
			

GsonHttpMessageConverter

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 MappingJackson2HttpMessageConverter both support application/json by default. Because of this, you should only add one JSON message converter to a RestTemplate instance. RestTemplate will use the first converter it finds that matches the specified mime type, so including both could produce unintended results.

Include the following dependency in your classpath to enable the GsonHttpMessageConverter.

Gradle:

dependencies {
    compile('com.google.code.gson:gson:${version}')
}
			

Maven:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>${gson-version}</version>
</dependency>
			

2.7 Usage Examples

Using RestTemplate, it is 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/spring-projects/spring-android-samples.git
	

2.7.1 Basic Usage Example

The following example shows a query to google for the search term "Spring Framework".

String url = "https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={query}";
			
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response to a String
String result = restTemplate.getForObject(url, String.class, "Spring Framework");
		

2.7.2 Using Gzip Compression

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.

// Add the gzip Accept-Encoding header
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAcceptEncoding(ContentCodingType.GZIP);
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response to a String
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.

// Add the identity Accept-Encoding header
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAcceptEncoding(ContentCodingType.IDENTITY);
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response to a String
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
		

2.7.3 Retrieving JSON data via HTTP GET

Suppose you have defined a Java object you wish to populate from a RESTful web request that returns JSON content. Marshaling JSON content requires Jackson or Gson to be available on the classpath.

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:

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response from JSON to an array of Events
Event[] events = restTemplate.getForObject(url, Event[].class);
		

You can also set the Accept header for the request:

// Set the Accept header
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAccept(Collections.singletonList(new MediaType("application","json")));
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response from JSON to an array of Events
ResponseEntity<Event[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Event[].class);
Event[] events = responseEntity.getBody();
		

2.7.4 Retrieving XML data via HTTP GET

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, you 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:

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response from XML to an EventList object
EventList eventList = restTemplate.getForObject(url, EventList.class);
		

You can also specify the Accept header for the request:

// Set the Accept header
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAccept(Collections.singletonList(new MediaType("application","xml")));
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP GET request, marshaling the response from XML to an EventList
ResponseEntity<EventList> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, EventList.class);
EventList eventList = responseEntity.getBody();
		

2.7.5 Send JSON data via HTTP POST

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:

// Create and populate a simple object to be used in the request
Message message = new Message();
message.setId(555);
message.setSubject("test subject");
message.setText("test text");

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP POST request, marshaling the request to JSON, and the response to a String
String response = restTemplate.postForObject(url, message, String.class);
		

You can also specify the Content-Type header in your request:

// Create and populate a simple object to be used in the request
Message message = new Message();
message.setId(555);
message.setSubject("test subject");
message.setText("test text");

// Set the Content-Type header
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(new MediaType("application","json"));
HttpEntity<Message> requestEntity = new HttpEntity<Message>(message, requestHeaders);

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

// Make the HTTP POST request, marshaling the request to JSON, and the response to a String
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
String result = responseEntity.getBody();
		

2.7.6 HTTP Basic Authentication

This example illustrates how to populate the HTTP Basic Authentication header with the username and password. If the username and password are accepted, then you will receive the response from the request. If they are not accepted, then the server is supposed to return an HTTP 401 Unauthorized response. Internally, RestTemplate handles the response, then throws an HttpClientErrorException. By calling getStatusCode() on this exception, you can determine the exact cause and handle it appropriately.

// Set the username and password for creating a Basic Auth request
HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(authHeader);
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);

// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();

try {
    // Make the HTTP GET request to the Basic Auth protected URL
    ResponseEntity<Message> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
    return response.getBody();
} catch (HttpClientErrorException e) {
    Log.e(TAG, e.getLocalizedMessage(), e);
    // Handle 401 Unauthorized response
}