Table of Contents
This section introduces the JAX-RS Client API, which is a fluent Java based API for communication with RESTful Web services. This standard API that is also part of Java EE 7 is designed to make it very easy to consume a Web service exposed via HTTP protocol and enables developers to concisely and efficiently implement portable client-side solutions that leverage existing and well established client-side HTTP connector implementations.
The JAX-RS client API can be utilized to consume any Web service exposed on top of a HTTP protocol or it's extension (e.g. WebDAV), and is not restricted to services implemented using JAX-RS. Yet, developers familiar with JAX-RS should find the client API complementary to their services, especially if the client API is utilized by those services themselves, or to test those services. The JAX-RS client API finds inspiration in the proprietary Jersey 1.x Client API and developers familiar with the Jersey 1.x Client API should find it easy to understand all the concepts introduced in the new JAX-RS Client API.
The goals of the client API are threefold:
Encapsulate a key constraint of the REST architectural style, namely the Uniform Interface Constraint and associated data elements, as client-side Java artifacts;
Make it as easy to consume RESTful Web services exposed over HTTP, same as the JAX-RS server-side API makes it easy to develop RESTful Web services; and
Share common concepts and extensibility points of the JAX-RS API between the server and the client side programming models.
As an extension to the standard JAX-RS Client API, the Jersey Client API supports a pluggable architecture to enable the
use of different underlying HTTP client Connector implementations. Several such implementations are
currently provided with Jersey. We have a default client connector using
with the JDK as well as connector implementations based on Apache HTTP Client, and Grizzly Asynchronous Client.
The uniform interface constraint bounds the architecture of RESTful Web services so that a client, such as a browser, can utilize the same interface to communicate with any service. This is a very powerful concept in software engineering that makes Web-based search engines and service mash-ups possible. It induces properties such as:
simplicity, the architecture is easier to understand and maintain; and
evolvability or loose coupling, clients and services can evolve over time perhaps in new and unexpected ways, while retaining backwards compatibility.
Further constraints are required:
every resource is identified by a URI;
a client interacts with the resource via HTTP requests and responses using a fixed set of HTTP methods;
one or more representations can be returned and are identified by media types; and
the contents of which can link to further resources.
The above process repeated over and again should be familiar to anyone who has used a browser to fill in HTML forms and follow links. That same process is applicable to non-browser based clients.
Many existing Java-based client APIs, such as the Apache HTTP client API or
supplied with the JDK place too much focus on the Client-Server constraint for the exchanges of request and
responses rather than a resource, identified by a URI, and the use of a fixed set of HTTP methods.
A resource in the JAX-RS client API is an instance of the Java class
and encapsulates an URI. The fixed set of HTTP methods can be invoked based on the
The representations are Java types, instances of which, may contain links that new instances of
WebTarget may be created from.
Since a JAX-RS component is represented as an annotated Java type, it makes it easy to configure, pass around and inject in ways that are not so intuitive or possible with other client-side APIs. The Jersey Client API reuses many aspects of the JAX-RS and the Jersey implementation such as:
Built-in support for Java types of representations such as
JAXB beans as well as additional Jersey-specific JSON and Multi Part support.
Using the fluent builder-style API pattern to make it easier to construct requests.
Some APIs, like the Apache HTTP Client or HttpURLConnection
can be rather hard to use and/or require too much code to do something relatively simple, especially when
the client needs to understand different payload representations.
This is why the Jersey implementation of JAX-RS Client API provides support for wrapping
and the Apache HTTP client. Thus it is possible to get the benefits of the established JAX-RS implementations and
features while getting the ease of use benefit of the simple design of the JAX-RS client API.
For example, with a low-level HTTP client library, sending a POST request with a bunch of typed HTML form parameters
and receiving a response de-serialized into a JAXB bean is not straightforward at all. With the new JAX-RS Client API
supported by Jersey this task is very easy:
Example 5.1. POST request with form parameters
Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://localhost:9998").path("resource"); Form form = new Form(); form.param("x", "foo"); form.param("y", "bar"); MyJAXBBean bean = target.request(MediaType.APPLICATION_JSON_TYPE) .post(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE), MyJAXBBean.class);
In the Example 5.1, “POST request with form parameters” a new
WebTarget instance is created using a new
Client instance first, next a Form instance is created with two form parameters.
Once ready, the
Form instance is
POSTed to the target resource.
First, the acceptable media type is specified in the
request(...) method. Then in the
post(...) method, a call to a static method on JAX-RS Entity is made to construct
the request entity instance and attach the proper content media type to the form entity that is being sent. The
second parameter in the
post(...) method specifies the Java type of the response entity that should
be returned from the method in case of a successful response. In this case an instance of JAXB bean is requested to
be returned on success. The Jersey client API takes care of selecting the proper MessageBodyWriter<T> for
the serialization of the
Form instance, invoking the
POST request and producing and
de-serialization of the response message payload into an instance of a JAXB bean using a proper
If the code above had to be written using
HttpUrlConnection, the developer would have to write custom
code to serialize the form data that are sent within the POST request and de-serialize the response input stream
into a JAXB bean. Additionally, more code would have to be written to make it easy to reuse the logic when
communicating with the same resource
“http://localhost:8080/resource” that is represented by
WebTarget instance in our example.
Refer to the dependencies for details on the dependencies when using the Jersey JAX-RS Client support.
You may also want to use a custom Connector implementation. In such case you would need to include
additional dependencies on the module(s) containing the custom client connector that you want to use. See section
"Configuring custom Connectors" about how to use and configure a custom
Jersey client transport
JAX-RS Client API is a designed to allow fluent programming model. This means, a construction of a
Client instance, from which a
WebTarget is created, from which a
request Invocation is built and invoked can be chained in a single "flow" of invocations.
The individual steps of the flow will be shown in the following sections.
To utilize the client API it is first necessary to build an instance of a
Client using one of the static ClientBuilder factory methods. Here's the most
Client client = ClientBuilder.newClient();
ClientBuilder is a JAX-RS API used to create new instances of
In a slightly more advanced scenarios,
ClientBuilder can be used to configure additional
client instance properties, such as a SSL transport settings, if needed (see ???
Client instance can be configured during creation by passing a ClientConfig
ClientBuilder factory method.
ClientConfig implements Configurable and therefore it offers methods to register
providers (e.g. features or individual entity providers, filters or interceptors) and setup properties.
The following code shows a registration of custom client filters:
ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MyClientResponseFilter.class); clientConfig.register(new AnotherClientFilter()); Client client = ClientBuilder.newClient(clientConfig);
In the example, filters are registered using the
ClientConfig.register(...) method. There are
multiple overloaded versions of the method that support registration of feature and provider classes or instances.
ClientConfig instance is configured, it can be passed to the
ClientBuilder to create a pre-configured
Note that the Jersey
ClientConfig supports the fluent API model of Configurable.
With that the code that configures a new client instance can be also written using a more compact style as shown
Client client = ClientBuilder.newClient(new ClientConfig() .register(MyClientResponseFilter.class) .register(new AnotherClientFilter());
The ability to leverage this compact pattern is inherent to all JAX-RS and Jersey Client API components.
Client implements Configurable interface too, it can be configured further
even after it has been created. Important is to mention that any configuration change done on a
Client instance will not influence the ClientConfig instance that was used to
provide the initial
Client instance configuration at the instance creation time.
The next piece of code shows a configuration of an existing
Similarly to earlier examples, since
Client.register(...) method supports the fluent API style,
multiple client instance configuration calls can be chained:
client.register(FilterA.class) .register(new FilterB()) .property("my-property", true);
To get the current configuration of the
Client instance a
method can be used.
ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MyClientResponseFilter.class); clientConfig.register(new AnotherClientFilter()); Client client = ClientBuilder.newClient(clientConfig); client.register(ThirdClientFilter.class); Configuration newConfiguration = client.getConfiguration();
In the code, an additional
MyClientResponseFilter class and
AnotherClientFilter instance are registered in the
clientConfig is then used to construct a new
Client instance. The
ThirdClientFilter is added separately to the constructed
This does not influence the configuration represented by the original
In the last step a
newConfiguration is retrieved from the
configuration contains all three registered filters while the original
still contains only two filters. Unlike
clientConfig created separately, the
newConfiguration retrieved from the
client instance represents a live
client configuration view. Any additional configuration changes made to the
are also reflected in the
newConfiguration is really
a view of the
client configuration and not a configuration state copy. These principles are
important in the client API and will be used in the following sections too. For example, you can construct a
common base configuration for all clients (in our case it would be
then reuse this common configuration instance to configure multiple
client instances that can
be further specialized. Similarly, you can use an existing
client instance configuration to
configure another client instance without having to worry about any side effects in the original
Once you have a
Client instance you can create a
WebTarget from it.
WebTarget webTarget = client.target("http://example.com/rest");
Client contains several
target(...) methods that allow for creation of
WebTarget instance. In this case we're using
target(String uri) version.
uri passed to the method as a
String is the URI of the targeted
web resource. In more complex scenarios it could be the context root URI of the whole RESTful application, from
WebTarget instances representing individual resource targets can be derived and
individually configured. This is possible, because JAX-RS
WebTarget also implements
WebTarget webTarget = client.target("http://example.com/rest"); webTarget.register(FilterForExampleCom.class);
The configuration principles used in JAX-RS client API apply to
WebTarget as well. Each
WebTarget instance inherits a configuration from it's parent (either a client or another
web target) and can be further custom-configured without affecting the configuration of the parent component.
In this case, the
FilterForExampleCom will be registered only in the
webTarget and not in
client. So, the
can still be used to create new
WebTarget instances pointing at other URIs using just the
common client configuration, which
FilterForExampleCom filter is not part of.
Let's assume we have a
webTarget pointing at
that represents a context root of a RESTful application and there is a resource exposed on the URI
"http://example.com/rest/resource". As already mentioned, a
instance can be used to derive other web targets. Use the following code to define a path to the resource.
WebTarget resourceWebTarget = webTarget.path("resource");
resourceWebTarget now points to the resource on URI
"http://example.com/rest/resource". Again if we configure the
resourceWebTarget with a filter specific to the
it will not influence the original
webTarget instance. However, the filter
FilterForExampleCom registration will still be inherited by the
resourceWebTarget as it has been created from
webTarget. This mechanism
allows you to share the common configuration of related resources (typically hosted under the same URI root,
in our case represented by the
webTarget instance), while allowing for further configuration
specialization based on the specific requirements of each individual resource. The same configuration principles
of inheritance (to allow common config propagation) and decoupling (to allow individual config customization)
applies to all components in JAX-RS Client API discussed below.
Let's say there is a sub resource on the path
You can derive a
WebTarget for this resource simply by:
WebTarget helloworldWebTarget = resourceWebTarget.path("helloworld");
Let's assume that the
helloworld resource accepts a query param for
requests which defines the greeting message. The next code snippet shows a code that creates
WebTarget with the query param defined.
WebTarget helloworldWebTargetWithQueryParam = helloworldWebTarget.queryParam("greeting", "Hi World!");
Please note that apart from methods that can derive new
WebTarget instance based on a URI path
or query parameters, the JAX-RS
WebTarget API contains also methods for working with matrix
Let's now focus on invoking a
GET HTTP request on the created web targets. To start building a new
HTTP request invocation, we need to create a new Invocation.Builder.
Invocation.Builder invocationBuilder = helloworldWebTargetWithQueryParam.request(MediaType.TEXT_PLAIN_TYPE); invocationBuilder.header("some-header", "true");
A new invocation builder instance is created using one of the
request(...) methods that are
WebTarget. A couple of these methods accept parameters that let you define
the media type of the representation requested to be returned from the resource. Here we are saying that we
"text/plain" type. This tells Jersey to add a
HTTP header to our request.
invocationBuilder is used to setup request specific parameters. Here we can setup headers
for the request or for example cookie parameters. In our example we set up a
header to value
Once finished with request customizations, it's time to invoke the request. We have two options now.
We can use the
Invocation.Builder to build a generic Invocation instance
that will be invoked some time later. Using
Invocation we will be able to e.g. set additional
request properties which are properties in a batch of several requests and use the generic JAX-RS
Invocation API to invoke the batch of requests without actually knowing all the details
(such as request HTTP method, configuration etc.). Any properties set on an invocation instance can be read
during the request processing. For example, in a custom ClientRequestFilter you can call
getProperty() method on the supplied ClientRequestContext to read a request
property. Note that these request properties are different from the configuration properties set on
Configurable. As mentioned earlier, an
Invocation instance provides generic
invocation API to invoke the HTTP request it represents either synchronously or asynchronously. See
the Chapter 10, Asynchronous Services and Clients for more information on asynchronous invocations.
In case you do not want to do any batch processing on your HTTP request invocations prior to invoking them, there
is another, more convenient approach that you can use to invoke your requests directly from an
Invocation.Builder instance. This approach is demonstrated in the next Java code listing.
Response response = invocationBuilder.get();
While short, the code in the example performs multiple actions. First, it will build the the request from the
invocationBuilder. The URI of request will be
http://example.com/rest/resource/helloworld?greeting="Hi%20World!" and the request will contain
some-header: true and
Accept: text/plain headers. The request will then pass
trough all configured request filters (
FilterForExampleCom). Once processed by the filters, the request will be sent to the remote
resource. Let's say the resource then returns an HTTP 200 message with a plain text response content that contains
the value sent in the request
greeting query parameter. Now we can observe the returned
which will produce the following output to the console:
200 Hi World!
As we can see, the request was successfully processed (code 200) and returned an entity (representation) is
"Hi World!". Note that since ve have configured a
in the resource target, when
response.readEntity(String.class) gets called, the response
returned from the remote endpoint is passed through the response filter chain (including the
MyClientResponseFilter) and entity interceptor chain and at last a proper
MessageBodyReader<T> is located to read the response content bytes from the response stream into a
String instance. Check Chapter 9, Filters and Interceptors to lear more about
request and response filters and entity interceptors.
Imagine now that you would like to invoke a
POST request but without any query parameters. You would
just use the
helloworldWebTarget instance created earlier and call the
post() instead of
Response postResponse = helloworldWebTarget.request(MediaType.TEXT_PLAIN_TYPE) .post(Entity.entity("A string entity to be POSTed", MediaType.TEXT_PLAIN));
The following code puts together the pieces used in the earlier examples.
Example 5.2. Using JAX-RS Client API
ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MyClientResponseFilter.class); clientConfig.register(new AnotherClientFilter()); Client client = ClientBuilder.newClient(clientConfig); client.register(ThirdClientFilter.class); WebTarget webTarget = client.target("http://example.com/rest"); webTarget.register(FilterForExampleCom.class); WebTarget resourceWebTarget = webTarget.path("resource"); WebTarget helloworldWebTarget = resourceWebTarget.path("helloworld"); WebTarget helloworldWebTargetWithQueryParam = helloworldWebTarget.queryParam("greeting", "Hi World!"); Invocation.Builder invocationBuilder = helloworldWebTargetWithQueryParam.request(MediaType.TEXT_PLAIN_TYPE); invocationBuilder.header("some-header", "true"); Response response = invocationBuilder.get(); System.out.println(response.getStatus()); System.out.println(response.readEntity(String.class));
Now we can try to leverage the fluent API style to write this code in a more compact way.
Example 5.3. Using JAX-RS Client API fluently
Client client = ClientBuilder.newClient(new ClientConfig() .register(MyClientResponseFilter.class) .register(new AnotherClientFilter())); String entity = client.target("http://example.com/rest") .register(FilterForExampleCom.class) .path("resource/helloworld") .queryParam("greeting", "Hi World!") .request(MediaType.TEXT_PLAIN_TYPE) .header("some-header", "true") .get(String.class);
The code above does the same thing except it skips the generic
Response processing and directly
requests an entity in the last
get(String.class) method call. This shortcut method let's you
specify that (in case the response was returned successfully with a HTTP 2xx status code) the response entity
should be returned as Java
String type. This compact example demonstrates another advantage of
the JAX-RS client API. The fluency of JAX-RS Client API is convenient especially with simple use cases.
Here is another a very simple GET request returning a String representation (entity):
String responseEntity = ClientBuilder.newClient() .target("http://example.com").path("resource/rest") .request().get(String.class);
All the Java types and representations supported by default on the Jersey server side for requests and responses are also supported on the client side. For example, to process a response entity (or representation) as a stream of bytes use InputStream as follows:
InputStream in = response.readEntity(InputStream.class); ... // Read from the stream in.close();
Note that it is important to close the stream after processing so that resources are freed up.
POST a file use a
File instance as follows:
File f = ... ... webTarget.request().post(Entity.entity(f, MediaType.TEXT_PLAIN_TYPE));
The support for new application-defined representations as Java types requires the implementation of the same JAX-RS entity provider extension interfaces as for the server side JAX-RS API, namely MessageBodyReader<T> and MessageBodyWriter<T> respectively, for request and response entities (or inbound and outbound representations).
Classes or implementations of the provider-based interfaces need to be registered as providers within the
JAX-RS or Jersey Client API components that implement
ClientConfig), as was shown in the earlier sections.
Some media types are provided in the form of JAX-RS Feature a concept that allows the extension
providers to group together multiple different extension providers and/or configuration properties in order
to simplify the registration and configuration of the provided feature by the end users. For example,
MoxyJsonFeature can be register to enable and configure JSON binding support via MOXy
By default, the transport layer in Jersey is provided by
HttpUrlConnection. This transport is implemented
in Jersey via HttpUrlConnector that implements Jersey-specific Connector SPI.
You can implement and/or register your own
Connector instance to the Jersey
Client implementation, that will replace the default
transport layer. Jersey provides several alternative client transport connector implementations that are ready-to-use.
You can use ApacheConnector (add a maven dependency to
or GrizzlyConnector (add a maven dependency to
org.glassfish.jersey.connectors:jersey-grizzly-connector) alternatively. Please, note again, that
the Connector SPI is not a feature of JAX-RS but is a Jersey-specific extension API that will only
work with Jersey. Following example shows how to setup the custom
Connector to the Jersey client.
ClientConfig clientConfig = new ClientConfig(); Connector connector = new GrizzlyConnector(clientConfig); clientConfig.connector(connector); Client client = ClientBuilder.newClient(clientConfig);
Client accepts as as a constructor argument a
Configurable instance. Jersey
implementation of the
Configurable provider for the client is
By using the Jersey
ClientConfig you can configure the custom
GrizzlyConnector is used as a custom connector
in the example above. Please note that the connector cannot be registered as a provider
.register(...) at the moment.
Filtering requests and responses can provide useful lower-level concept focused on a certain independent aspect or domain that is decoupled from the application layer of building and sending requests, and processing responses. Filters can read/modify the request URI, headers and entity or read/modify the response status, headers and entity.
Jersey contains the following useful client-side filters that you may want to use in your applications:
|CsrfProtectionFilter: Cross-site request forgery protection filter (adds
|EncodingFeature: Feature that registers encoding filter which use registered ContentEncoders to encode and decode the communication. The encoding/decoding is performed in interceptor (you don't need to register this interceptor). Check the javadoc of the EncodingFeature in order to use it.|
|HttpBasicAuthFilter: HTTP Basic Authentication filter (see ??? below).|
Note that these features are provided by Jersey, but since they use and implement JAX-RS API, the features should be portable and run in any JAX-RS implementation, not just Jersey. See Chapter 9, Filters and Interceptors chapter for more information on filters and interceptors.
This section describes how to setup SSL configuration on Jersey client (using JAX-RS API). The SSL configuration is setup in ClientBuilder. The client builder contains methods for definition of KeyStore, TrustStore or entire SslContext. See the following example:
SSLContext ssl = ... your configured SSL context; Client client = ClientBuilder.newBuilder().sslContext(ssl).build(); Response response = client.target("https://example.com/resource").request().get();
The example above shows how to setup a custom
SslContext to the
SslContext can be more difficult as you might need to init instance properly with the protocol,
TrustStore, etc. Jersey offers a utility ClientConfig class that
can be used to setup the
SslConfigurator can be configured based on
standardized system properties for SSL configuration, so for example you can configure the
name using a environment variable
will use such a variable to setup the
SslContext. See javadoc of ClientConfig for more
details. The following code shows how a
SslConfigurator can be used to create a custom SSL
SslConfigurator sslConfig = SslConfigurator.newInstance() .trustStoreFile("./truststore_client") .trustStorePassword("secret-password-for-truststore") .keyStoreFile("./keystore_client") .keyPassword("secret-password-for-keystore"); SSLContext sslContext = sslConfig.createSSLContext(); Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
Note that you can also setup
TrustStore directly on a
ClientBuilder instance without wrapping them into the
SslContext. However, if you setup
SslContext it will override any previously defined
ClientBuilder also offers a method for defining a custom HostnameVerifier implementation.
HostnameVerifier implementations are invoked when default host URL verification fails.
Note that to utilize HTTP with SSL it is necessary to utilize the
Currently the default connector
HttpUrlConnector based on
support for SSL defined by JAX-RS configuration discussed in this sample.
Jersey contains a filter that allows client to authenticate to servers which requires HTTP Basic Authentication. Use HttpBasicAuthFilter to add authentication header to requests initiated from from the client. See the example of how to configure and register the filter:
client.register(new HttpBasicAuthFilter("Homer", "SecretPassword"));