Archives

Managed JAX-RS Client

Common use-case in web-application development is aggregating data from multiple resources, combining them together and returning them to the used as XML/JSON or as a web page. In Java world these (external) resources can be approached via standardized Clients from JAX-RS 2.0. Jersey 2 application can use so-called managed client mechanism that brings a convenient way to create JAX-RS clients and web targets for such resources.

In this article I’ll demonstrate the concepts on a simple application that displays ratings of movies obtained from different sources:

a class field for example in resources or providers (filters, interceptors, ..), i.e. RatingsResource:

Injecting WebTarget into class parameters.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@Path("/rating")

@Produces("text/html")

publicclassRatingsResource{

@CsfdClient

@Uri("movie/{id}")

privateWebTarget csfdMovie;

@ImdbClient

@Uri("http://omdbapi.com/?r={format}&t={search}")

privateWebTarget imdbMovie;

...

}

or a bean property.

As you probably noticed the value of @Uri can be either absolute or relative URI. The relative ones are resolved into absolute URIs in the context of application (context path) or in a context of enclosing resource class. Web target from the first example (internal/greeting/{greeting}) is pointing at an internal resource (present in the same application) but web target from the second example (movie/{id}) is not relative to our application as you’ll see in the next section.

Provided URIs can also contain template parameters (internal/greeting/{greeting}, r={format}&t={search}) which are resolved automatically (internal/greeting/{greeting}), if they are represented as path params (see @Path):

Configuring

By default, injected clients are configured with features and providers from the configuration of an application (i.e. MyApplication) that are also applicable to clients. In our case only JacksonFeature would be taken into consideration.

In case this is not enough for you need to take a look at @ClientBinding.

@ClientBinding

Meta-annotation that provides a facility for creating bindings between an @Uri-injectable web target instances and clients (and their configurations) that are used to create the injected web target instances.

So, basically, the first step is to create a custom client-binding annotation and put @ClientBinding on top of it, i.e. CsfdClient:

Custom client-binding annotation

1

2

3

4

5

6

7

8

9

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD,ElementType.PARAMETER})

@ClientBinding(

baseUri="http://csfdapi.cz/",

inheritServerProviders=false,

configClass=ManagedClientConfig.class

)

public@interfaceCsfdClient{

}

Second step is to annotate WebTarget with custom client-binding annotation along with @Uri, i.e. RatingsResource:

Injected WebTarget bound to configuration

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@Path("/rating")

@Produces("text/html")

publicclassRatingsResource{

@CsfdClient

@Uri("movie")

privateWebTarget csfdSearch;

@CsfdClient

@Uri("movie/{id}")

privateWebTarget csfdMovie;

...

}

Notice that one client (created for @CsfdClient) is used to create two WebTarget instances that are used separately.

web.xml

Parameters of @ClientBinding for particular client-binding annotation can be set declaratively in web.xml via init-param-eters. You need to remember to prefix parameter name with fully-qualified name of custom client-binding annotation:

The last highlighted init-parameter (sk.dejavu.jersey.sample.ImdbClient.property.format) shows special way how to define a property for the newly created client. In this case we can obtain value of the property from configuration of our web target and set the format of entities received from imdbMovie: