Jersey Client

RESTful

Jersey Client


1. Introduction

The Jersey client API is a high-level Java based API which gives the possibility to work with RESTful Web services. It can be used to work with any RESTful Web service and not only with services implemented by JAX-RS. 

A resource in the Jersey client API is an instance of the WebResource Java class, and encapsulates a URI. The fixed set of HTTP methods are methods on WebResource and the representations are Java types.

Let's look at the simplest Jersey RESTful web services client example:

Example 1.1. Send a POST request with form parameters

The example demonstrates how to post a Form with several parameters and receive the response in String format:

Form f = new Form();
f.add("id", "4");
f.add("name", "OCEJWSD 6");

Client client = Client.create();
WebResource resource = client.resource("http://localhost:8080/exams");
String response = resource
       .type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
       .post(String.class, f);
System.out.print(response);

2. Overview of API 

Steps to create the client API are:

  1. Create an instance of a Client.
  2. Configure the Client if necessary.
  3. Create and configure the WebResource.
  4. Build a request.
  5. Receive a response.

Let's discuss each step in details:

2.1. Create an Instance of a Client

Example 2.1. Create a client instance

Client client = Client.create();

2.2. Configure a Client

Example 2.2. Configure a client changing properties

The client instance can be configured by setting properties on the map returned from the getProperties methods:

Client client = Client.create();
Map<String, Object> properties = client.getProperties();
properties.put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);

Example 2.3. Configure a client with setter methods

Or it can be configured by invoking the specific setter methods:

Client client = Client.create();
client.setFollowRedirects(true);

Example 2.4. Configure a client with a ClientConfig object

The third way to configure a Client instance is by creating a ClientConfig object:

ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getProperties().put(
       ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);
Client client = Client.create(clientConfig);

2.3. Create and configure a WebResource

A new WebResource can be created from a Client instance or from an existing WebResource.

Example 2.5. Create a WebResource from a Client

The example creates a reference to a web resource with the URI "http://localhost:8080/exams" :

WebResource resource = client.resource("http://localhost:8080/exams");

Example 2.6. Create a new WebResource from a WebResource 

A new WebResource can be created from an existing WebResource by building from the its URI. This example shows how to add a new path segment and query parameters and results in a GET request to the URI "http://localhost:8080/exams/1?option1=value1&option2=value2".

Client client = Client.create();
WebResource resource = client.resource("http://localhost:8080/exams");
resource.accept(MediaType.APPLICATION_XML_TYPE,
        MediaType.APPLICATION_JSON_TYPE);

MultivaluedMap<String, String> params = new MultivaluedMapImpl();
params.add("option1", "value1");
params.add("option2", "value2");

String response = resource.path("1").
        queryParams(params).
        get(String.class);

A WebResource instance will inherit the configuration declared on the client instance.

Client instances are expensive resources, so it is recommended to reuse a configured client instance for the creation of Web resources.

The creation of Web resources, the building of requests and receiving of responses are guaranteed to be thread safe. It means that a Client and WebResource instances can be shared between multiple threads.

2.4. Build a Request and receive a Response

Requests to a Web resource are built using the builder pattern (RequestBuilder) where the terminating method corresponds to an HTTP method (UniformInterface). If the response has an entity then its Java type is declared in the terminating HTTP method. 

Example 2.7. Build a GET request

The example sends a GET request with an Accept header of application/xml, application/json and a non-standard header MyHeader of "Jersey Client". A response entity of String type is expected.

String response = resource.accept(MediaType.APPLICATION_XML_TYPE,
       MediaType.APPLICATION_JSON_TYPE).
       header("MyHeader", "Jersey Client").
       get(String.class);

Example 2.8. Build a POST request

PUT, POST and DELETE requests contain a request entity. An instance of an entity Java type can be declared in the terminating HTTP method as showed in the example. This example demonstrate how to declare the Content-Type of the request entity with type builder method

String response = resource.accept(MediaType.APPLICATION_XML_TYPE,
        MediaType.APPLICATION_JSON_TYPE).
        header("MyHeader", "Jersey Client").
        type(MediaType.TEXT_PLAIN_TYPE).
        post(String.class, "request entity content");

Example 2.9. Declare an Entity and Content-Type with entity method

This example declare an entity and Content-Type of the request with entity method:

String response = resource.accept(MediaType.APPLICATION_XML_TYPE,
        MediaType.APPLICATION_JSON_TYPE).
        header("MyHeader", "Jersey Client").
        entity("request entity content", MediaType.TEXT_PLAIN_TYPE).
        post(String.class);

Example 2.10. Declare an Entity and Content-Type with entity method

The ClientResponse class is used if it is required to receive not only the entity but such information as response status, headers and entity tag:

Client client = Client.create();
WebResource resource = client.resource("http://localhost:8080/exams");
resource.accept(MediaType.APPLICATION_XML_TYPE,
        MediaType.APPLICATION_JSON_TYPE);
ClientResponse response = resource.get(ClientResponse.class);
        
System.out.println(response.getEntityTag());
System.out.println(response.getEntity(String.class));
System.out.println(response.getHeaders());
System.out.println(response.getStatus());

Example 2.11. Declare an Entity and Content-Type with entity method

If the ClientResponse type is not used and the response status is greater than or equal to 300 then the runtime exception UniformInterfaceException is thrown. This exception can be caught and the ClientResponse received:

try {
   String entity = resource.get(String.class);
} catch (UniformInterfaceException exception) {
   ClientResponse response = exception.getResponse();
}

3. Java Instances and Types for Representations

All the Java types for representations supported by the Jersey server side for requests and responses are also supported on the client side. Find the list of supported java types in JAX-RS article. 

Example 3.1. Receive an InputStream as a Response Entity

The get method of the resource in the example returns the content of the file using InputStream:

@GET
public InputStream get() {
    InputStream fileInStream = null;
    try {
        fileInStream = new FileInputStream("someFile.xml");
    } catch (IOException e) {
        System.out.println(e);
    }
    return fileInStream;
}

Let's look at the client code to process a response entity as a stream of bytes with the help of InputStream:

Client client = Client.create();
WebResource resource = client.resource(".../exams");
InputStream in = resource.get(InputStream.class);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String str = null;
while ((str = bufferedReader.readLine()) != null) {
   System.out.println(str);
}
in.close();

WebResource.get method receives InputStream.class as a parameter. The InputStream is converted to BufferedReader and the content of the stream is printed to the console. The stream is closed in the end.

Example 3.2. Post a File

This example shows how to post a File to a resource. First let's look at the resource's post method, which has File as a method parameter. The BufferedReader is created to read from the file. The method returns the content of the file in the String format (that doesn't make senese in the real life).

@POST
public String post(File file) {
    StringBuilder result = new StringBuilder("");
    try {
       BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
       String str = null;
       while ((str = bufferedReader.readLine()) != null) {
            result.append(str);
       }
       bufferedReader.close();
     } catch (IOException e) {
         System.out.print(e);
         result.append(e.getMessage());
     }
     return result.toString();
}

And the code of the Jersey client:

Client client = Client.create();
WebResource resource = client.resource(".../exams");
File file = new File("someFile.xml");
String result = resource.post(String.class, file);
System.out.println(result);

Example 3.3. Add support for new representations as a provider class

To support new representations, user need to implement MessageBodyReader or MessageBodyWriter (more about it read in JAX-RS Entity Providers) and register them with ClientConfig:

ClientConfig clientConfig = new DefaultClientConfig();
Set<Class<?>> classes = clientConfig.getClasses();
classes.add(ExamMessageBodyWriter.class);

Example 3.4. Add support for new representations as singleton

Another way to register entity provider is to add it to ClientConfig as singleton:

ClientConfig clientConfig = new DefaultClientConfig();
ExamMessageBodyWriter writer = new ExamMessageBodyWriter();
clientConfig.getSingletons().add(writer);

4. Filters

The Jersey Client API gives the possibility to add filters, which can read and modify requests and responses.

  • It is possible to add filters to the Client and WebResource.
  • A WebResource inherits filters of its creator - it can be a Client or another WebResource.
  • For requests, filters are applied in reverse order, starting with the WebResource filters and then moving to the inherited filters.
  • For responses, filters are applied starting with inherited filters and followed by the filters added to the WebResource.

Example 4.1. Add filters

This examples shows how to add filters to the client and WebResources. There are two filters added to the client  - filter1 and filter2, and filter3 is added to the WebResource.

After building a request, it is filtered by filter3, filter2 and filter1 in that order. After building the response, it is filtered by filter1, filter2 and filter3 in that order, before the response is returned.

ClientFilter filter1 = ...
ClientFilter filter2 = ...
Client c = Client.create();
c.addFilter(filter1);
c.addFilter(filter2);
    
ClientFilter filter3 = ...
WebResource r = c.resource(...);
r.addFilter(filter3);

Example 4.2. Basic template for a filter

The filter modifies the request by creating a new ClientRequest or modifying the state of the passed ClientRequest before calling the next filter. The call to the next request will return the response, a Jersey ClientResponse. The filter modifies the response by creating a new ClientResponse or modifying the state of the returned ClientResponse. Then the filter returns the modified response.

    class MyClientFilter extends ClientFilter {
        public ClientResponse handle(ClientRequest cr) {
            // Modify the request
            ClientRequest mcr = modifyRequest(cr);
            // Call the next filter
            ClientResponse resp = getNext().handle(mcr);
            // Modify the response
            return modifyResponse(resp);
        }
    }

The Jersey Client API supports two filters:

  1. A GZIPContentEncodingFilter. If this filter is added then a request entity is compressed with the Content-Encoding of gzip, and a response entity if compressed with a Content-Encoding of gzip is decompressed. The filter declares an Accept-Encoding of gzip.
  2. A LoggingFilter. If this filter is added then the request and response headers as well as the entities are logged to a declared output stream if present, or to System.out if not. Often this filter will be placed at the end of the ordered list of filters to log the request before it is sent and the response after it is received.

Sources:  Jersey Tutorial - Client API



0 comments
Leave your comment: