Learn to create an Apache HttpClient Android client
Summary: Create JAX-RS web service access with the Apache HttpClient library. Jersey, a reference implementation for JAX-RS, simplifies development of RESTful web services in the Java™ environment. Android is a popular smartphone and this article shows you how to create a JAX-RS client for Android. You'll create an Apache HttpClient library client to a JAX-RS web service.
Introduction
The REST software architecture is based on transferring representation of resources. RESTful web services offer some advantages: They are simple, lightweight, and fast. A RESTful web service exposes a set of resources identified by URIs. Resources respond to the HTTP methods GET, POST, PUT, and DELETE. Resources may be accessed in various formats, such as HTML, plain text, XML, PDF, JPEG, or JSON. The Java API for RESTful web services (JAX-RS) is defined in JSR 311. Jersey is a reference implementation for JAX-RS that simplifies development of RESTful web services in Java.
In this article, use the Apache HttpClient library to create a JAX-RS client for Android—the popular smartphone platform. You candownload the sample code used in this article.
Back to top
Setting up the environment
Before you can create a client for a JAX-RS web service, you need to set up the environment. See Resources for links.
Jersey is built using JDK 6.0, so you also need to install JDK 6.0.
CLASSPATH
of the application/web server. C:\Jersey\jersey-bundle-1.4.jar;C:\Jersey\jersey-archive-1.4\lib\asm-3.1.jar; C:\Jersey\jersey-archive-1.4\lib\jsr311-api-1.1.1.jar |
Back to top
Creating an Eclipse project
In this section, you will create a web project and add the JAX-RS facet to the project. Use the following steps to create an Eclipse project.
AndroidJAX-RS
, select the default Content Directory, and click Finish. A Dynamic Web Project is created and gets added to Project Explorer. Right-click on the project node and selectProperties.
A user library is added. Click Add JARs to add Jersey JARs to the user library. As in Figure 4, add the following Jersey JARs:
com.sun.jersey.spi.container.servlet.ServletContainer
, as in Figure 5. Click OK. The targeted runtimes are configured with the JAX-RS project facet. Click OK in the Properties dialog.
The JAX-RS User libraries get added to the project, and the JAX-RS servlet and servlet mapping get configured in web.xml. You need to add init-param
elements for the com.sun.jersey.config.property.resourceConfigClass
and thecom.sun.jersey.config.property.packages
init parameters. Listing 2 shows the web.xml
.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/ xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <servlet> <description>JAX-RS Tools Generated - Do not modify</description> <servlet-name>JAX-RS Servlet</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name> <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value> </init-param> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>jaxrs</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>JAX-RS Servlet</servlet-name> <url-pattern>/jaxrs/*</url-pattern> </servlet-mapping> </web-app> |
Back to top
Creating and running a resource class
The next step is to create a RESTful web service resource using a root resource class. A root resource class is a POJO annotated with the @PATH
annotation. It consists of at least one method annotated with the @PATH
annotation or @GET
, @PUT
, @POST
or@DELETE
.
AndroidJAX-RS/src
jaxrs
HelloWorldResource
Click Finish.
Annotate the Java class with the @PATH
annotation. The code in Listing 3 specifies the URI path on which the Java class shall be hosted as /helloworld
.
@Path("/helloworld") public class HelloWorldResource { ... } |
To add resource methods to produce three different MIME types, add the getClichedMessage()
, getXMLMessage()
, andgetHTMLMessage()
methods. Annotate each method with the @GET
annotation, which indicates that the methods shall process HTTP GET requests. Specify String
as the return type for each of the methods. Annotate each method with the @PRODUCES
annotation, and specify a different MIME type for each method.
Now you want to output a "Hello JAX-RS" method using the MIME types text/plain
, text/xml
, and text/html
. The getXMLMessage
method is annotated with the @Produces
("text/xml"
) annotation that produces an XML message. Uncomment only one of the methods annotated with the @GET
method. If no other distinguishing path component is specified, the @GET
request is routed to the method annotated with @GET
. If multiple methods match a request URI, the JAX-RS selection algorithm is used to select the resource method. For example, you can specify multiple methods with the @GET
annotation by using a different path
id for the methods annotated with @GET
. Listing 4 shows the root resource class.
package jaxrs; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; // The Java class will be hosted at the URI path //"/helloworld" @Path("/helloworld") public class HelloWorldResource { // The Java method will process HTTP GET requests @GET // The Java method will produce content identified by the MIME Media // type "text/plain" @Produces("text/plain") public String getClichedMessage() { // Return some cliched textual content return "Hello Android"; } // @GET // @Produces("text/xml") // public String getXMLMessage() { // return "<?xml version=\"1.0\"?>" + "<hello> Hello Android" + "</hello>"; // } // @GET //@Produces("text/html") //public String getHTMLMessage() { //return "<html> " + "<title>" + "Hello Android" + "</title>" // + "<body><h1>" + "Hello Android" + "</body></h1>" + "</html> "; // } } |
Run the resource class to produce different types of output. Comment out the methods that are not to be tested, and keep one method uncommented for each of the test runs. First, test the text/xml
MIME type as output. Start the application/web server if not already started. Right-click on the resource class and select Run As > Run on Server, as in Figure 8.
On the server, the init parameter com.sun.jersey.config.property.resourceConfigClass
is initiated ascom.sun.jersey.api.core.PackagesResourceConfig
and the init parameter com.sun.jersey.config.property.packages
is initiated as jaxrs
, as specified in web.xml. The root resource class jaxrs.HelloWorldResource
is found. The Jersey application v1.4 is initiated, and the AndroidJAX-RS module deploys on the server.
Back to top
Creating an Android client project
In this section you'll create an Android project in which you create the JAX-RS client for Android.
AndroidJAXRSClient
AndroidJAXRSClient
and Package name android.jaxrs
AndroidJAXRSClient
. An activity represents a user interaction, and the class extending the Activity class creates a window for a UI.
8
The files in the Android project are:
AndroidJAXRSClient
), which extends the Activity
class In the res/layout/main.xml file, specify the layout of the Android UI components. Create a LinearLayout
withandroid:orientation="vertical"
. You'll create a UI in which the response from the web service is displayed as a text message. Add a TextView
element with id jaxrs
to display the JAX-WS web service response for a method call to one of the get
methods. The method invocation gets a Hello message as a response in either XML, HTML, or text. Listing 5 shows the main.xml file:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/jaxrs" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> |
To access the JAX-RS web service from an Android device, enable the android.permission.INTERNET
permission, in AndroidManifest.xml, which allows applications to open network sockets. Add the uses-permission
element in Listing 6.
<uses-permission android:name="android.permission.INTERNET"></uses-permission> |
Specify the minimum Android version with the uses-sdk
element. The AndroidJAXRSClient
activity, the intent-filter
, and action
are specified with the activity
element and sub-elements. Listing 7 shows the AndroidManifest.xml file.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.jaxrs" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".AndroidJAXRSClient" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="8" /> <uses-permission android:name="android.permission.INTERNET"></uses-permission> </manifest> |
The Android SDK includes the Apache HttpClient library. Import the classes in Listing 8 into AndroidJAXRSClient
.
org.apache.http.HttpEntity; org.apache.http.HttpResponse; org.apache.http.client.ClientProtocolException; org.apache.http.client.HttpClient; org.apache.http.client.methods.HttpGet; org.apache.http.impl.client.DefaultHttpClient; |
The AndroidJAXRSClient
class extends the Activity
class. The onCreate(Bundle savedInstanceState)
method is invoked when the activity is first called. Define the user interface using the setContentView
method and the layout resource, as in Listing 9.
setContentView(R.layout.main); |
Listing 10 shows how to create an Android widget TextView
object, using the findViewById
method on the TextView
element, with the id jaxrs
that was defined in main.xml.
TextView jaxrs = (TextView) findViewById(R.id.jaxrs); |
The default implementation of HttpClient
is DefaultHttpClient
. Create a DefaultHttpClient
object, as Listing 11.
HttpClient httpclient = new DefaultHttpClient(); |
Create an HttpGet
object to retrieve information from the server, as in Listing 12. Specify the URL to the resource hosted on the URI path /helloworld
. Specify the IP address for host instead of localhost. The client runs on the Android device, and localhost for the Android device is not the host on which the JAX-RS web service runs (unless the JAX-RS web service is also hosted on the Android device, which is not the case in this example).
HttpGet request = new HttpGet("http://192.168.1.68:7001/AndroidJAX-RS/jaxrs/helloworld"); |
Specify acceptable media types using the Accept
header. Set only one of the media types, which corresponds to the media type produced in the JAX-RS web service, in the Accept
header. In the first run, set the Accept
header to text/xml
to output thetext/xml
response, as in Listing 13.
request.addHeader("Accept", "text/xml"); //request.addHeader("Accept", "text/html"); //request.addHeader("Accept", "text/plain"); |
Test the output of each of the response types (plain text, html, and XML). The accepted response type should match the MIME type produced in the resource class. The MIME type produced by the resource class should match an acceptable MIME type. If the produced MIME type and the acceptable MIME type do not match, a com.sun.jersey.api.client.UniformInterfaceException
is generated. For example, set the acceptable MIME type to text/xml
and the produced MIME type to application/xml
. TheUniformInterfaceException
is generated. As in Listing 14, invoke the execute()
method of the HttpClient
, with the HttpGet
method as an argument, to retrieve the HttpResponse
object.
HttpResponse response = httpclient.execute(request); |
From the HttpResponse
obtain the HttpEntity
using the getEntity
method (Listing 15).
HttpEntity entity = response.getEntity(); |
Get the content as an InputStream
from the HttpGet
using the getContent()
method (Listing 16).
InputStream
from the HttpEntity
InputStream instream = entity.getContent(); |
Create a StringBuilder
for the message returned from the JAX-RS web service (Listing 17).
StringBuilder sb = new StringBuilder(); |
Create a BufferedReader
from the InputStream
(Listing 18).
BufferedReader r = new BufferedReader(new InputStreamReader(instream)); |
Read each line from the BufferedReader
and add it to the StringBuilder
(Listing 19).
for (String line = r.readLine(); line != null; line = r.readLine()) { sb.append(line); } |
Get the String
message from the StringBuilder
and close the InputStream
(Listing 20).
String jaxrsmessage = sb.toString(); instream.close(); |
Set the String
message on the TextView
UI component (Listing 21).
jaxrs.setText(jaxrsmessage); |
Listing 22 shows the AndroidJAXRSClient
class.
package android.jaxrs; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; public class AndroidJAXRSClient extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView jaxrs = (TextView) findViewById(R.id.jaxrs); try { HttpClient httpclient = new DefaultHttpClient(); HttpGet request = new HttpGet( "http://192.168.1.68:7001/AndroidJAX-RS/jaxrs/helloworld"); //request.addHeader("Accept", "text/html"); // request.addHeader("Accept", "text/xml"); request.addHeader("Accept", "text/plain"); HttpResponse response = httpclient.execute(request); HttpEntity entity = response.getEntity(); InputStream instream = entity.getContent(); String jaxrsmessage = read(instream); jaxrs.setText(jaxrsmessage); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static String read(InputStream instream) { StringBuilder sb = null; try { sb = new StringBuilder(); BufferedReader r = new BufferedReader(new InputStreamReader( instream)); for (String line = r.readLine(); line != null; line = r.readLine()) { sb.append(line); } instream.close(); } catch (IOException e) { } return sb.toString(); } } |
Figure 10 shows the directory structure of the Android client application. (View a larger version of Figure 10.)
Back to top
Running the Android client
Now you're ready to run the Android client to invoke the JAX-RS web service and output the XML message. Right-click on theAndroidJAXRSClient project and select Run As > Android Application, as in Figure 11.
The Android AVD starts and the JAX-RS client application installs on the Android device, as in Figure 12.
The AndroidJAXRSClient
activity starts, and the XML message produced by the JAX-RS web service resource is output to the Android device, as in Figure 13.
Similarly, the HTML message is the output if the method that produces the text/html
media type is uncommented in the resource class and the Accept
header is set to receive the same media type. For example, in the resource class, uncomment the method in Listing 23.
@GET @Produces("text/html") public String getHTMLMessage() { return "<html> " + "<title>" + "Hello Android" + "</title>" + "<body><h1>" + "Hello Android" + "</body></h1>" + "</html> "; } |
In the client class, uncomment the addHeader
invocation in Listing 24.
request.addHeader("Accept", "text/html"); |
Rerun the AndroidJAXRSClient
application to get the HTML response, as in Figure 14.
To get the text response, uncomment the method in the resource class in Listing 25.
@GET @Produces("text/plain") public String getClichedMessage() { return "Hello Android"; } |
In the client class, uncomment the following Accept
header media type setting in Listing 26.
request.addHeader("Accept", "text/plain"); |
Rerun the AndroidJAXRSClient
application to get the text message output, as in Figure 15.
Back to top
Summary
In this article, you learned how to create a JAX-RS web service and invoke the web service from an Android client. You sent XML, HTML, and text output to the Android device.