Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.


{span:style=
Span
Wiki Markup
style
font-size:2em;font-weight:bold
} JAX-RS : Client API


Table of Contents

Maven Dependency

Code Block
xml
xml
 API {span}

{toc}
h1. Maven Dependency
{code:xml}
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-client</artifactId>
  <version>3.0.0-milestone1<15</version>
</dependency>
{code}

In

...

CXF

...

2.7.x

...

no

...

JAX-RS

...

2.0

...

Client

...

API

...

is

...

supported

...

and

...

CXF

...

specific

...

Client

...

API

...

is

...

located

...

in

...

the

...

cxf-rt-frontend-jaxrs

...

module.

...

CXF

...

Apache

...

HttpClient

...

based

...

transport

...

is

...

required

...

to

...

get

...

the

...

asynchronous

...

invocations

...

working

...

correctly:

Code Block
xml
xml


{code:xml}
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http-hc</artifactId>
  <!-- 2.7.8 or 3.0.0-milestone115 --> 
  <version>${cxf.version}</version>
</dependency>
{code}


h1. 

JAX-RS

...

2.0

...

Client

...

API

...

CXF

...

3.0.0

...

implements

...

JAX-RS

...

2.0

...

Client

...

API.

...

Internally

...

it

...

is

...

implemented

...

in

...

terms

...

of

...

CXF

...

specific

...

WebClient.

...

The

...

javax.ws.rs.client provides a short overview of how JAX-RS 2.0 Client API works.

Typically, one starts from ClientBuilder in order to create a Client.
Next WebTarget is created and further customized as needed.

Next, Invocation.Builder is initialized and the request can be made immediately using one of the SyncInvoker methods, with the builder directly implementing SyncInvoker.

Code Block
java
java
Client client = ClientBuilder.newBuilder().newClient();
WebTarget target = client.target("http://localhost:8080/rs");
target = target.path("service").queryParam("a", "avalue");

Invocation.Builder builder = target.request();
Response response = builder.get();
Book book = builder.get(Book.class);

The above sequence can be easily collapsed into a single code sequence if preferred.
Note that SyncInvoker (and AsyncInvoker) expects Entity to represent the request body.

Invocation.Builder has a shortcut to Invocation via its build(...) methods to further customize the invocation.

Invocation.Builder.async() links to AsyncInvoker.

Client and WebTarget are all can be individually configured, the implement Configurable interface which can accept the providers and properties and return Configuration. Configuring the Client directly or indirectly via ClientBuilder.withConfig method affects all the WebClients spawned by a given Client.

JAX-RS 2.0 and CXF specific API

CXF proxy and WebClient client code has been retrofitted to support JAX-RS 2.0 client filters, reader and writer interceptors, new exception classes and Response API.

WebClient offers shortcuts to JAX-RS 2.0 AsyncInvoker and SyncInvoker interfaces.

WebClient.getConfig(Object client) supports JAX-RS 2.0 WebTarget and Invocation.Builder for 2.0 clients to be able to get to the lower-level CXF configuration and set up the properties such as 'receiveTimeout', etc.

Proxy-based API

With the proxy-based API, one can reuse on the client side the interfaces or even the resource classes which have already been designed for processing the HTTP requests on the server side (note that a cglib-nodeps dependency will need to be available on the classpath for proxies created from concrete classes). When reused on the client side, they simply act as remote proxies.

JAXRSClientFactory is a utility class which wraps JAXRSClientFactoryBean. JAXRSClientFactory offers a number of utility methods but JAXRSClientFactoryBean can also be used directly if desired.

For example, given these class definitions:

Code Block
java
java
@Path("/bookstore")
public interface BookStore {
   @GET
   Books getAllBooks();
   
   @Path("{id}")
   BookResource getBookSubresource(@PathParam("id") long id) throws NoBookFoundException;
}

public class BookStoreImpl implements BookStore {
   public Books getAllBooks() {}
   
   public BookResource getBookSubresource(long id) throws NoBookFoundException {}
}

public interface BookResource {
   @GET
   Book getBook();
}

public class BookResourceImpl implements BookResource {
   Book getBook() {}
}

the following client code retrieves a Book with id '1' and a collection of books:

Code Block
java
java
BookStore store = JAXRSClientFactory.create("http://bookstore.com", BookStore.class);
// (1) remote GET call to http://bookstore.com/bookstore
Books books = store.getAllBooks();
// (2) no remote call
BookResource subresource = store.getBookSubresource(1);
// {3} remote GET call to http://bookstore.com/bookstore/1
Book b = subresource.getBook();

When proxies are created, initially or when subresource methods are invoked, the current URI is updated with corresponding @Path, @PathParam, @QueryParam or @MatrixParam values, while @HttpHeader and @CookieParam values contribute to the current set of HTTP headers. Same happens before the remote invocation is done.

It is important to understand that strictly speaking there is no direct relationship between a given method on the client side and the same one on the server side. The job of the proxy is to construct a correct URI according to given class and method specifications - it may or may not be the same method on the corresponding server class that will be invoked (provided of course that it is a JAX-RS annotated server resource class - but that may not be the case!) More often than not, you will see a method foo() invoked on a server resource class whenever the same method is invoked on the corresponding remote proxy - but in the presence of @Path annotations with arbitrary regular expressions this is not guaranteed, however this doesn't matter, as the most important thing is that a proxy will produce a correct URI and it will be matched as expected by a server class.

Client-side MessageBodyReaders and MessageBodyWriters are used to process request or response bodies just as they do on the server side. More specifically, method body writers are invoked whenever a remote method parameter is assumed to be a request body (that is, it has no JAX-RS annotations attached) or when a form submission is emulated with the help of either @FormParams or the JAX-RS MultivaluedMap.

You can make multiple remote invocations on the same proxy (initial or subresource), the current URI and headers will be updated properly for each call.

If you would like to proxify concrete classes such as BookStoreImpl for example (say you can not extract interfaces), then drop the cglib-nodeps.jar on a classpath. Such classes must have a default constructor. All methods which have nothing to do with JAX-RS will simply be ignored on the client side and marked as unsupported.

Customizing proxies

Proxies end up implementing not only the interface requested at proxy creation time but also a Client interface. In many cases one does not need to explicitly specify commonly used HTTP headers such as Content-Type or Accept as this information will likely be available from @Consumes or @Produces annotations. At the same time you may explicitly set either of these headers, or indeed some other header. You can use a simple WebClient utility method for converting a proxy to a base client:

Code Block
java
java
|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/package-frame.html] provides a short overview of how JAX-RS 2.0 Client API works.

Typically, one starts from [ClientBuilder|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/ClientBuilder.html] in order to create a [Client|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/Client.html]. 
Next [WebTarget|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/WebTarget.html] is created and further customized as needed. 

Next, [Invocation.Builder|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/Invocation.Builder.html] is initialized and the request can be made immediately using one of the [SyncInvoker|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/SyncInvoker.html] methods, with the builder directly implementing SyncInvoker.

{code:java}
Client client = ClientBuilder.newBuilder().newClient();
WebTarget target = client.target("http://localhost:8080/rs");
target = target.path("service").queryParam("a", "avalue");

Invocation.Builder builder = target.request();
Response response = builder.get();
Book book = builder.get(Book.class);

{code}

The above sequence can be easily collapsed into a single code sequence if preferred.
Note that SyncInvoker (and AsyncInvoker) expects [Entity|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/Entity.html] to represent the request body.

Invocation.Builder has a shortcut to [Invocation|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/Invocation.html] via its build(...) methods to further customize the invocation.
  
Invocation.Builder.async() links to AsyncInvoker.

Client and WebTarget are all can be individually configured, the implement [Configurable|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/core/Configurable.html] interface which can accept the providers and properties and return [Configuration|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/core/Configuration.html]. Configuring the Client directly or indirectly via ClientBuilder.withConfig method affects all the WebClients spawned by a given Client. 

h2. JAX-RS 2.0 and CXF specific API

CXF proxy and WebClient client code has been retrofitted to support JAX-RS 2.0 client filters, reader and writer interceptors, new exception classes and Response API.

WebClient offers shortcuts to JAX-RS 2.0 [AsyncInvoker|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/AsyncInvoker.html] and [SyncInvoker|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/SyncInvoker.html] interfaces.

WebClient.getConfig(Object client) supports JAX-RS 2.0 [WebTarget|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/WebTarget.html] and [Invocation.Builder|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/Invocation.Builder.html] for 2.0 clients to be able to get to the lower-level CXF configuration and set up the properties such as 'receiveTimeout', etc.   

h1. Proxy-based API

With the proxy-based API, one can reuse on the client side the interfaces or even the resource classes which have already been designed for processing the HTTP requests on the server side (note that a [cglib|http://cglib.sourceforge.net/]-nodeps dependency will need to be available on the classpath for proxies created from concrete classes). When reused on the client side, they simply act as remote proxies.

[JAXRSClientFactory|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java] is a utility class which wraps [JAXRSClientFactoryBean|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java]. JAXRSClientFactory offers a number of utility methods but JAXRSClientFactoryBean can also be used directly if desired.

For example, given these class definitions:

{code:java}
@Path("/bookstore")
public interface BookStore {
   @GET
   Books getAllBooks();
   
   @Path("{id}")
   BookResource getBookSubresource(@PathParam("id") long id) throws NoBookFoundException;
}

public class BookStoreImpl implements BookStore {
   public Books getAllBooks() {}
   
   public Book getBookSubresource(long id) throws NoBookFoundException {}
}

public interface BookResource {
   @GET
   Book getBook();
}

public class BookResourceImpl implements BookResource {
   Book getBook() {}
}

{code}

the following client code retrieves a Book with id '1' and a collection of books: 

{code:java}
BookStore store = JAXRSClientFactory.create("http://bookstore.com", BookStore.class);
// (1) remote GET call to http://bookstore.com/bookstore
Books books = store.getAllBooks();
// (2) no remote call
BookResource subresource = store.getBookSubresource(1);
// {3} remote GET call to http://bookstore.com/bookstore/1
Book b = subresource.getBook();
{code}     

When proxies are created, initially or when subresource methods are invoked, the current URI is updated with corresponding \@Path, \@PathParam, \@QueryParam or @MatrixParam values, while \@HttpHeader and \@CookieParam values contribute to the current set of HTTP headers. Same happens before the remote invocation is done. 

It is important to understand that strictly speaking there is no direct relationship between a given method on the client side and the same one on the server side. The job of the proxy is to construct a correct URI according to given class and method specifications - it may or may not be the same method on the corresponding server class that will be invoked (provided of course that it is a JAX-RS annotated server resource class - but that may not be the case!) More often than not, you will see a method foo() invoked on a server resource class whenever the same method is invoked on the corresponding remote proxy - but in the presence of \@Path annotations with arbitrary regular expressions this is not guaranteed, however this doesn't matter, as the most important thing is that a proxy will produce a correct URI and it will be matched as *expected* by a server class.   

Client-side MessageBodyReaders and MessageBodyWriters are used to process request or response bodies just as they do on the server side. More specifically, method body writers are invoked whenever a remote method parameter is assumed to be a request body (that is, it has no JAX-RS annotations attached) or when a form submission is emulated with the help of either \@FormParams or the JAX-RS MultivaluedMap. 

You can make multiple remote invocations on the same proxy (initial or subresource), the current URI and headers will be updated properly for each call. 

If you would like to proxify concrete classes such as BookStoreImpl for example (say you can not extract interfaces), then drop the cglib-nodeps.jar on a classpath. Such classes must have a default constructor. All methods which have nothing to do with JAX-RS will simply be ignored on the client side and marked as unsupported.

h2. Customizing proxies 

Proxies end up implementing not only the interface requested at proxy creation time but also a [Client|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java] interface. In many cases one does not need to explicitly specify commonly used HTTP headers such as Content-Type or Accept as this information will likely be available from \@Consumes or \@Produces annotations. At the same time you may explicitly set either of these headers, or indeed some other header. You can use a simple [WebClient|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java] utility method for converting a proxy to a base client:

{code:java}
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
WebClient.client(proxy).accept("text/xml");
// continue using the proxy    
{code}

You

...

can

...

also

...

check

...

a

...

current

...

set

...

of

...

headers,

...

current

...

and

...

base

...

URIs

...

and

...

a

...

client

...

Response.

...

Converting

...

proxies

...

to

...

Web

...

Clients

...

and

...

vice

...

versa

...

Using

...

proxies

...

is

...

just

...

one

...

way

...

to

...

consume

...

a

...

service.

...

Proxies

...

hide

...

away

...

the

...

details

...

of

...

how

...

URIs

...

are

...

being

...

composed

...

while

...

HTTP-centric

...

WebClients

...

provide

...

for

...

an

...

explicit

...

URI

...

creation.

...

Both

...

proxies

...

and

...

http

...

clients

...

rely

...

on

...

the

...

same

...

base

...

information

...

such

...

as

...

headers

...

and

...

the

...

current

...

URI

...

so

...

at

...

any

...

moment

...

of

...

time

...

you

...

can

...

create

...

a

...

WebClient

...

instance

...

out

...

of

...

the

...

existing

...

proxy:

Code Block
java
java


{code:java}
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
Client client = WebClient.client(proxy);
WebClient httpClient = WebClient.fromClient(client);
// continue using the http client    
{code}

At

...

any

...

moment

...

of

...

time

...

you

...

can

...

convert

...

an

...

http

...

client

...

into

...

a

...

proxy

...

too:

Code Block
java
java


{code:java}
BookStore proxy1 = JAXRSClientFactory.create("http://books", BookStore.class);
Client client = WebClient.client(proxy1);
BookStore proxy2 = JAXRSClientFactory.fromClient(client, BookStore.class);
{code}

h2. Handling exceptions

There are a couple of ways you can handle remote exceptions with proxies.
One approach is to register a [ResponseExceptionMapper|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java] as a provider either from Spring using a jaxrs:client or using a corresponding JAXRSClientFactory utility method. This way you can map remote error codes to expected checked exceptions or runtime exceptions if needed.
 
If no ResponseExceptionMapper is available when a remote invocation failed then an instance of 

Handling exceptions

There are a couple of ways you can handle remote exceptions with proxies.
One approach is to register a ResponseExceptionMapper as a provider either from Spring using a jaxrs:client or using a corresponding JAXRSClientFactory utility method. This way you can map remote error codes to expected checked exceptions or runtime exceptions if needed.

If no ResponseExceptionMapper is available when a remote invocation failed then an instance of javax.ws.rs.WebApplicationException

...

will

...

be

...

thrown

...

(Note

...

org.apache.cxf.jaxrs.client.ServerWebApplicationException

...

is

...

used

...

to

...

represent

...

the

...

server

...

exceptions

...

before

...

CXF

...

2.7.0.).

...

At

...

this

...

point

...

of

...

time

...

you

...

can

...

check

...

the

...

actual

...

Response

...

and

...

proceed

...

from

...

there:

Code Block
java
java


{code:java}
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
try {
    proxy.getBook();
} catch(WebApplicationException ex) {
  Response r = ex.getResponse();
  String message = ex.getMessage();
}
{code}

javax.ws.rs.ProcessingException

...

will

...

be

...

thrown

...

if

...

the

...

exception

...

has

...

occurred

...

for

...

one

...

of

...

two

...

reasons:

...

  • the

...

  • remote

...

  • invocation

...

  • succeeded

...

  • but

...

  • no

...

  • proper

...

  • MessageBodyReader

...

  • has

...

  • been

...

  • found

...

  • on

...

  • the

...

  • client

...

  • side;

...

  • in

...

  • this

...

  • case

...

  • the

...

  • Response

...

  • object

...

  • representing

...

  • the

...

  • result of the invocation will still be available
  • the remote invocation has failed for whatever reasons on the client side, example, no MessageBodyWriter is available.

Note org.apache.cxf.jaxrs.client.ClientWebApplicationException is used to represent the client processing exceptions before CXF 2.7.0.

Configuring proxies in Spring

When creating a proxy with JAXRSClientFactory, you can pass a Spring configuration location as one of the arguments. Or you can create a default bus using Spring configuration and all proxies will pick it up:

Code Block
java
java
SpringBusFactory bf = new SpringBusFactory();
Bus bus = bf.createBus("org/apache/cxf/systest/jaxrs/security/jaxrs-https.xml");
BusFactory.setDefaultBus(bus);
// BookStore proxy will get the configuration from Spring
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);

Injecting proxies

For injecting proxies via a spring context, use the jaxrs:client element like:

Code Block
xml
xml
<jaxrs:client id="restClient"
    address="http://localhost:${testutil.ports.BookServerRestSoap}/test/services/rest"
    serviceClass="org.apache.cxf.systest.jaxrs.BookStoreJaxrsJaxws"
    inheritHeaders="true">
    <jaxrs:headers>
        <entry key="Accept" value="text/xml"/>
    </jaxrs:headers>
</jaxrs:client>  

See this bean for a full example of how jaxrs:client can be used to inject a proxy. Note that WebClient can also be injected as a jaxrs:client.


Asynchronous proxy invocations

Starting from CXF 3.1.7 it is possible to do the asynchronous proxy invocations. One needs to register JAX-RS 2.0 InvocationCallback as a proxy request context property:

Code Block
java
java
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);

Book book = null;
final InvocationCallback<Book> callback = new InvocationCallback<Book>() {
  public void completed(Book response) {
     book = response;
  }
  public void failed(Throwable error) {
  }
};


WebClient.getConfig(proxy).getRequestContext().put(InvocationCallback.class.getName(), callback);
assertNull(proxy.getBook());
Thread.sleep(3);
assertNotNull(book);

If you have a proxy with different methods returning different response types then either register an Object bound InvocationCallback or register a collection of type-specific callbacks:

Code Block
java
java
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);

// Book
Book book = null;
final InvocationCallback<Book> bookCallback = new InvocationCallback<Book>() {
  public void completed(Book response) {
     book = response;
  }
  public void failed(Throwable error) {
  }
};
// Chapter
Chapter chapter = null;
final InvocationCallback<Chapter> chapterCallback = new InvocationCallback<Chapter>() {
  public void completed(Chapter response) {
     chapter = response;
  }
  public void failed(Throwable error) {
  }
};
 
WebClient.getConfig(proxy).getRequestContext().put(InvocationCallback.class.getName(), 
                            of the invocation will still be available
- the remote invocation has failed for whatever reasons on the client side, example, no MessageBodyWriter is available.

Note org.apache.cxf.jaxrs.client.ClientWebApplicationException is used to represent the client processing exceptions before CXF 2.7.0.

h2. Configuring proxies in Spring

When creating a proxy with JAXRSClientFactory, you can pass a Spring configuration location as one of the arguments. Or you can create a default bus using Spring configuration and all proxies will pick it up:

{code:java}
SpringBusFactory bf = new SpringBusFactory();
Bus bus = bf.createBus("org/apache/cxf/systest/jaxrs/security/jaxrs-https.xml");
BusFactory.setDefaultBus(bus);
// BookStore proxy will get the configuration from Spring
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
{code} 

h2. Injecting proxies

For injecting proxies via a spring context, use the jaxrs:client element like:
{code:xml}
  <jaxrs:client id="restClient"
         address="http://localhost:${testutil.ports.BookServerRestSoap}/test/services/rest"
         serviceClass="org.apache.cxf.systest.jaxrs.BookStoreJaxrsJaxws"
         inheritHeaders="true">
         <jaxrs:headers>
             <entry key="Accept" value="text/xml"/>
         </jaxrs:headers>
  </jaxrs:client>  
{code}

See this [bean|http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_soap_rest/WEB-INF/beans.xml] for a full example of how jaxrs:client can be used to inject a proxy 

h2. Limitations

Proxy sub-resource methods returning Objects can not be invoked. Prefer to have sub-resource methods returning typed classes: interfaces, abstract classes or concrete implementations. 

*The following applies to CXF 2.6.x-2.4.x only*:

When a proxy method returning a JAX-RS Response is invoked, the returned Response.getEntity() will return a response InputStream by default. Starting with CXF 2.3.2 one can register an org.apache.cxf.jaxrs.client.ResponseReader provider and cast the Response.getEntity() to more specific application classes:

{code:java}
ResponseReader reader = new ResponseReader();
reader.setEntityClass(Book.class);
        
BookStore bs = JAXRSClientFactory.create("http://localhost:8080/books", BookStore.class,
                        Arrays.asList(bookCallback, chapterCallback));
// Get Book
assertNull(proxy.getBook(123L));
Thread.sleep(3);
assertNotNull(book);
 
// Get             Collections.singletonList(readerBook Chapter
assertNull(proxy.getBookChapter(123L));
Response r1 = bs.getBook("123"Thread.sleep(3);
Book book = (Book)r1.getEntity();

reader.setEntityClass(Author.class);
Response r2 = bs.getBookAuthor("123");
Author book = (Author)r2.getEntity();
{code}

h2. Working with user models

Proxies can be created with the external user model being applied to a proxy class, forassertNotNull(chapter);

Make sure a proxy is created in a thread safe mode if it is being accessed by multiple threads for every new request thread to have its own callback.

Buffering Responses

One way to buffer proxy responses is to have a proxy method return JAX-RS Response, use its bufferEntity()  method (available in JAX-RS 2.0) and use Response.readEntity which can return typed responses if preferred.

The other option is to have a "buffer.proxy.response" property enabled on a given proxy instance.

Limitations

Proxy sub-resource methods returning Objects can not be invoked. Prefer to have sub-resource methods returning typed classes: interfaces, abstract classes or concrete implementations.


Working with user models

Proxies can be created with the external user model being applied to a proxy class, for example:

Code Block
java
java
 example:

{code:java}
JAXRSClientFactory.createFromModel("http://books", BookNoAnnotations.class, "classpath:/resources/model.xml", null);
{code}

BookNoAnnotations is either an interface or concrete class with no ;

BookNoAnnotations is either an interface or concrete class with no JAX-RS

...

annotations.

...

Both

...

client

...

proxies

...

and

...

server

...

endpoints

...

can

...

'turn'

...

it

...

into

...

a

...

RESTful

...

resource

...

by

...

applying

...

an

...

external

...

user

...

model.

CXF WebClient API

HTTP centric clients are WebClient instances which also implement the Client interface. In addition to setting various Client request properties, you can also make an explicit HTTP invocation with an HTTP verb being the name of a given operation :

Code Block
java
java


h1. CXF WebClient API

HTTP centric clients are [WebClient|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java] instances which also implement the [Client|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java] interface. In addition to setting various Client request properties, you can also make an explicit HTTP invocation with an HTTP verb being the name of a given operation :

{code:java}
WebClient client = WebClient.create("http://books");
Book book = client.path("bookstore/books").accept("text/xml").get(Book.class);
{code}

You

...

can

...

choose

...

to

...

get

...

an

...

explicit

...

JAX-RS

...

Response

...

instead

...

and

...

check

...

the

...

response

...

code,

...

headers

...

or

...

entity

...

body

...

if

...

any:

Code Block
java
java


{code:java}
WebClient client = WebClient.create("http://books");
client.path("bookstore/books");
client.type("text/xml").accept("text/xml")
Response r = client.post(new Book());
Book b = r.readEntity(Book.class);
{code}

WebClient

...

lets

...

you

...

get

...

back

...

to

...

a

...

base

...

URI

...

or

...

to

...

a

...

previous

...

path

...

segment

...

and

...

move

...

forward,

...

it

...

can

...

be

...

handy

...

for

...

getting

...

a

...

number

...

of

...

individual

...

entries

...

from

...

a

...

service

...

with

...

ids

...

embedded

...

in

...

path

...

segments

...

:

Code Block
java
java


{code:java}
WebClient client = WebClient.create("http://books");
List<Book> books = getBooks(client, 1L, 2L, 3L)

private List<Book> getBooks(WebClient client, Long ...ids) {
   List<Book> books = new ArrayList<Book>(); 
   for (Long id : ids) {
       books.add(client.path(id).get(Book.class));
       client.back(); 
   } 
   return books;
}
{code}

The

...

above

...

code

...

will

...

send

...

requests

...

like

...

"GET

...

http://books/1",

...

"GET

...

http://books/2",

...

etc.

...

If

...

the

...

request

...

URI

...

can

...

be

...

parameterized

...

then

...

you

...

may

...

want

...

to

...

use

...

the

...

following

...

code:

Code Block
java
java


{code:java}
Book book = WebClient.create("http://books").path("{year}/{id}", 2010, 123).get(Book.class);
// as opposed to
// WebClient.create("http://books").path(2010).path(123).get(Book.class);
{code}


When reusing the same WebClient instance for multiple invocations, one may want to reset its state with the help of the reset() method, for example, when the Accept header value needs to be changed and the current URI needs to be reset to the baseURI (as an alternative to a back(true) call). The resetQuery() method may be used to reset the query values only. Both options are available for proxies too.

{anchor:asynchronousinvocations}
h2. Asynchronous invocations

WebClient has several methods accepting JAX-RS 2.0 [InvocationCallback|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/InvocationCallback.html] and returning Future. Alternatively, users can also use WebClient.async() shortcut to work with a standard [AsyncInvoker|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/client/AsyncInvoker.html].

h2. Working with explicit collections

WebClient supports [GenericEntity|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/core/GenericEntity.html] and JAX-RS 2.0 [GenericType|https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/core/GenericType.html] directly and via JAX-RS 2.0 SyncInvoker and AsyncInvoker to make it easier to work with the explicit collections.

WebClient also has few collection-aware methods, example:

{code:java}

When reusing the same WebClient instance for multiple invocations, one may want to reset its state with the help of the reset() method, for example, when the Accept header value needs to be changed and the current URI needs to be reset to the baseURI (as an alternative to a back(true) call). The resetQuery() method may be used to reset the query values only. Both options are available for proxies too.

Anchor
asynchronousinvocations
asynchronousinvocations

Asynchronous invocations

WebClient has several methods accepting JAX-RS 2.0 InvocationCallback and returning Future. Alternatively, users can also use WebClient.async() shortcut to work with a standard AsyncInvoker.

Working with explicit collections

WebClient supports GenericEntity and JAX-RS 2.0 GenericType directly and via JAX-RS 2.0 SyncInvoker and AsyncInvoker to make it easier to work with the explicit collections.

WebClient also has few collection-aware methods, example:

Code Block
java
java
Collection<? extends Book> books = WebClient.getCollection(Book.class);
Collection<? extends Book> books = WebClient.postAndGetCollection(new ArrayList<Book>(), Book.class);

{code}

h2. Handling exceptions


You can handle remote exceptions by either explicitly getting a Response object as shown above and handling error statuses as needed or you can catch either 

Handling exceptions

You can handle remote exceptions by either explicitly getting a Response object as shown above and handling error statuses as needed or you can catch either javax.ws.rs.WebApplicationException

...

or

...

javax.ws.rs.ProcessingException

...

exceptions,

...

the

...

same

...

way

...

it

...

can

...

be done with proxies.

Configuring HTTP clients in Spring

Like proxies, HTTP clients can be created using a number of WebClient static utility methods: you can pass a location to a Spring configuration bean if needed or you can set up a default bus as shown above. For example:

Code Block
xml
xml
 done with proxies. 

h2. Configuring HTTP clients in Spring

Like proxies, HTTP clients can be created using a number of WebClient static utility methods: you can pass a location to a Spring configuration bean if needed or you can set up a default bus as shown above. For example:
{code:xml}
<bean id="myJsonProvider" 
class="org.apache.cxf.jaxrs.provider.JSONProvider" > 
        <property name="supportUnwrapped" value="true" /> 
        <property name="wrapperName" value="nodeName" /> 
    </bean> 

<util:list id="webClientProviders"> 
    <ref bean="myJsonProvider"/> 
</util:list> 

<bean id="myWebClient" class="org.apache.cxf.jaxrs.client.WebClient" 
factory-method="create"> 
        <constructor-arg type="java.lang.String" 
value="http://some.base.url.that.responds/" /> 
        <constructor-arg ref="webClientProviders" /> 
</bean> 
{code} 

Note,

...

starting

...

from

...

CXF

...

2.7.5

...

it

...

is

...

possible

...

to

...

set-up

...

WebClient

...

instances

...

the

...

same

...

way

...

as

...

proxies,

...

using

...

jaxrs:client:

Code Block
xml
xml


{code:xml}
<jaxrs:client id="webClient"
         address="https://localhost:${port}/services/rest"
         serviceClass="org.apache.cxf.jaxrs.client.WebClient">
         <jaxrs:headers>
             <entry key="Accept" value="text/xml"/>
         </jaxrs:headers>
  </jaxrs:client>
{code}

The

...

only

...

limitation

...

of

...

using

...

this

...

option

...

is

...

that

...

some

...

of

...

jaxrs:client

...

attributes

...

("inheritHeaders",

...

"modelRef")

...

and

...

elements

...

("model")

...

are

...

not

...

really

...

applicable

...

to

...

WebClient.

...

XML-centric

...

clients

...

XML-centric

...

clients

...

are

...

WebClients

...

using

...

an

...

XMLSource

...

utility

...

class.

...

XMLSource

...

has

...

a

...

number

...

of

...

methods

...

facilitating

...

the

...

retrieval

...

of

...

JAXB

...

beans,

...

individual

...

properties

...

or

...

links

...

with

...

the

...

help

...

of

...

XPath

...

expressions.

...

For

...

example:

Code Block
java
java


{code:java}
WebClient wc = WebClient.create("http://aggregated/data");
XMLSource source = wc.get(XMLSource.class);
source.setBuffering(true);
Book b1 = source.getNode("/books/book[position() = 1]", Book.class);
Book b2 = source.getNode("/books/book[position() = 2]", Book.class);
{code}

Note

...

that

...

an

...

XMLSource

...

instance

...

can

...

be

...

set

...

to

...

buffer

...

the

...

input

...

stream

...

thus

...

allowing

...

for

...

executing

...

multiple

...

XPath

...

queries.

...


XMlSource

...

can

...

also

...

help

...

with

...

getting

...

the

...

URIs

...

representing

...

the

...

links

...

or

...

XML

...

instances

...

as

...

Strings.

...

Support

...

for

...

arbitrary

...

HTTP

...

methods

...

for

...

sync

...

invocations.

...

To

...

get

...

the

...

arbitrary

...

HTTP

...

methods

...

supported

...

with

...

the

...

synchronous

...

client

...

calls or bypass some known Java HTTPUrlConnection issues (example it will block empty DELETE requests) add the HttpClient-based

...

transport

...

dependency

...

and

...

set

...

a

...

"use.async.http.conduit"

...

contextual

...

property.

...

This

...

will

...

work

...

as

...

is

...

for

...

asynchronous

...

calls

...

given

...

that

...

the

...

HttpClient-based

...

transport

...

is

...

required.

...

Thread Safety

Proxies and web clients (clients)

...

are

...

not

...

thread

...

safe

...

by

...

default.

...

In

...

some

...

cases

...

this

...

can

...

be

...

a

...

limitation,

...

especially

...

when

...

clients

...

are

...

injected;

...

synchronizing

...

on

...

them

...

can

...

cause

...

performance

...

side

...

effects.

...

One

...

way

...

to

...

'make'

...

clients

...

thread-safe

...

is

...

to

...

use

...

WebClient.fromClient(Client)

...

for

...

web

...

clients

...

or

...

JAXRSClientFactoryBean.fromClient()

...

factory

...

methods

...

which

...

copy

...

all

...

the

...

original

...

configuration

...

properties

...

and

...

can

...

be

...

used

...

to

...

create

...

new

...

client

...

instances

...

per

...

every

...

request.

...

A

...

single

...

client

...

doing

...

multiple

...

invocations

...

without

...

changing

...

the

...

current

...

URI

...

or headers is thread-safe (while creating a Invocation.Builder instances concurrently is not thread-safe since the shared instance of non-thread-safe class ClientProviderFactory is used under the hood). The only limitation in this case applies to proxies, in that they can not get "out of band" headers without synchronizing, ex :

Code Block
java
java
 headers is thread-safe. The only limitation in this case applies to proxies, in that they can not get "out of band" headers without synchronizing, ex :
{code:java}
// get some response headers passed to us 'out of band', which is not thread-safe for a plain proxy: 
String bookHeader = WebClient.toClientclient(injectedBookStoreProxy).getHeaders().getFirst("BookHeader"); 
{code}  

Final option is to use a 

Final option is to use a 'threadSafe'

...

boolean

...

property

...

when

...

creating

...

proxies

...

or

...

web

...

clients

...

(either

...

from

...

Spring

...

or

...

programmatically),

...

see

...

this

...

test

...

for

...

more

...

details.

...

Thread-safe

...

clients

...

created

...

this

...

way

...

keep

...

their

...

state

...

in

...

a

...

thread-local

...

storage.

...

If

...

a

...

number

...

of

...

incoming

...

threads

...

is

...

limited

...

then

...

one

...

option

...

is

...

just

...

do

...

nothing,

...

while

...

the

...

other

...

option

...

is

...

to

...

reset

...

the

...

thread

...

local

...

state

...

:

Code Block
java
java


{code:java}
try { 
   webClient.path("bar") 
   webClient.header("bar", baz); 
   webClient.invoke(...); 
} finally { 
   // if using a proxy: WebClient.client(proxy).reset(); 
   webClient.reset(); 
} 
{code}

Yet

...

another

...

option

...

is

...

to

...

use

...

JAXRSClientFactoryBean

...

and

...

a

...

'secondsToKeepState'

...

property

...

for

...

creating

...

thread-safe

...

clients

...

-

...

this

...

will

...

instruct

...

clients

...

to

...

clean-up

...

the

...

thread-local

...

state

...

periodically.

...

Configuring Clients at Runtime

Proxy and http-centric

...

clients

...

are

...

typically

...

created

...

by

...

JAXRSClientFactory

...

or

...

WebClient

...

factory

...

methods

...

but

...

JAXRSClientFactoryBean

...

can

...

also

...

be

...

used

...

for

...

pre-configuring

...

clients

...

before

...

they

...

are

...

created.

...

Sometimes,

...

you

...

may

...

want

...

to

...

configure

...

a

...

client

...

instance

...

after

...

it

...

is

...

been

...

created.

...

For

...

example,

...

one

...

may

...

want

...

to

...

configure

...

HTTPConduit

...

programmatically,

...

as

...

opposed

...

to

...

setting

...

its

...

properties

...

using

...

Spring.

...

ClientConfiguration

...

represents

...

a

...

client-specific

...

configuration

...

state

...

and

...

can

...

be accessed like this :

Code Block
java
java
Book proxy = JAXRSClientFactory.create("http://books", Book.class);
ClientConfiguration config = WebClient.getConfig(proxy);
HTTPConduit conduit1 = (HTTPConduit)config.getConduit();

WebClient webclient = WebClient accessed like this :

{code:java}
Book proxy = JAXRSClientFactory.create("http://books", Book.class);
ClientConfigurationHTTPConduit config = WebClient.getConfig(proxy);
HTTPConduit conduit1 = (HTTPConduit)config.getConduit();

WebClient webclient = WebClient.create("http://books");
HTTPConduit conduit2 = (HTTPConduit)WebClient.getConfig(webclient).getConduit();
{code}


h1. Creating clients programmatically with no Spring dependencies

Example :

{code:java}
conduit2 = (HTTPConduit)WebClient.getConfig(webclient).getConduit();

When working with JAX-RS 2.0 Client API one can set some low-level HTTP properties via Configurable interface:

Code Block
java
java
//http.connection.timeout
//http.receive.timeout
//http.proxy.server.uri
//http.proxy.server.port
Client client = ClientBuilder.newClient();
client.property("http.receive.timeout", 1000000); 

Creating clients programmatically with no Spring dependencies

Example :

Code Block
java
java
JAXRSClientFactoryBean sf = new JAXRSClientFactoryBean();
sf.setResourceClass(CustomerService.class);
sf.setAddress("http://localhost:9000/");
BindingFactoryManager manager = sf.getBus().getExtension(BindingFactoryManager.class);
JAXRSBindingFactory factory = new JAXRSBindingFactory();
factory.setBus(sf.getBus());
manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, factory);
CustomerService service = sf.create(CustomerService.class);
WebClient wc = sf.createWebClient();
{code} 


h1. Configuring an HTTP Conduit from Spring

Configuring an HTTP Conduit from Spring

There's

...

a

...

number

...

of

...

ways

...

to

...

configure

...

HTTPConduits

...

for

...

proxies

...

and

...

WebClients.

...

It

...

is

...

possible

...

to

...

have

...

an

...

HTTPConduit

...

configuration

...

which

...

will

...

apply

...

to

...

all

...

clients

...

using

...

different

...

request

...

URIs

...

or

...

only

...

to

...

those

...

with

...

using

...

a

...

specific

...

URI.

...

For

...

example:

Code Block
xml
xml


{code:xml}
<http:conduit name="http://books:9095/bookstore.*"/> 
{code}

This

...

configuration

...

will

...

affect

...

all

...

proxies

...

and

...

WebClients

...

which

...

have

...

requestURIs

...

starting

...

from

...

'http://books:9095/bookstore'.

...

Note

...

the

...

trailing

...

'.*'

...

suffix

...

in

...

the

...

name

...

of

...

the

...

http:conduit

...

element.

...

Please

...

see

...

this

...

configuration

...

file

...

for

...

more

...

examples.

...

Alternatively

...

you

...

can

...

just

...

do:

Code Block
xml
xml


{code:xml}
<http:conduit name="*.http-conduit"/> 
{code}

This

...

configuration

...

will

...

affect

...

all

...

the

...

clients,

...

irrespective

...

of

...

the

...

URIs

...

being

...

dealt

...

with.

...

If

...

you

...

work

...

with

...

proxies

...

then

...

you

...

can

...

have

...

the

...

proxy-specific

...

configuration

...

using

...

the

...

expanded

...

QName

...

notation:

Code Block
xml
xml


{code:xml}
<http:conduit name="{http://foo.bar}BookService.http-conduit"/> 
{code}

In

...

this

...

example,

...

'foo.bar'

...

is

...

a

...

reverse

...

package

...

name

...

of

...

the

...

BookService

...

proxy

...

class.

...

Similarly,

...

for

...

WebClients

...

you

...

can

...

do:

Code Block
xml
xml


{code:xml}
<http:conduit name="{http://localhost:8080}WebClient.http-conduit"/> 
{code}

In this example, 'http://localhost:8080' is the base service URI.

Please see [jaxrs-https-client1.xml|http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/jaxrs-https-client1.xml] and [jaxrs-https-client2.xml|http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/jaxrs-https-client2.xml] configuration files for more examples.

Also see [this wiki page|Client HTTP Transport (including SSL support)] on how to configure HTTPConduits.

h1. Clients and Authentication

Proxies and HTTP-centric clients can have the HTTP Authorization header set up explicitly:

{code:java}

// Replace 'user' and 'password' by the actual values
String authorizationHeader = "Basic " 
    + org.apache.cxf.common.util.Base64Utility.encode("user:password".getBytes());

// proxies
WebClient.client(proxy).header("Authorization", authorizationHeader);

// web clients
webClient.header("Authorization", authorizationHeader);

{code}

or by providing a username and password pair at client creation time, for example:
{code:java}
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class, "username", "password", "classpath:/config/https.xml");

WebClient client = WebClient.create("http://books", "username", "password", "classpath:/config/https.xml");
{code}

When injecting clients from Spring, one can add 'username' and 'password' values as attributes to jaxrs:client elements or add them to WebClient factory create methods.http-conduit"/> 

In this example, 'http://localhost:8080' is the base service URI.

Please see jaxrs-https-client1.xml and jaxrs-https-client2.xml configuration files for more examples.

Also see this wiki page on how to configure HTTPConduits.

Clients and Authentication

Proxies and HTTP-centric clients can have the HTTP Authorization header set up explicitly:

Code Block
java
java
// Replace 'user' and 'password' by the actual values
String authorizationHeader = "Basic " 
    + org.apache.cxf.common.util.Base64Utility.encode("user:password".getBytes());

// proxies
WebClient.client(proxy).header("Authorization", authorizationHeader);

// web clients
webClient.header("Authorization", authorizationHeader);

or by providing a username and password pair at client creation time, for example:

Code Block
java
java
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class, "username", "password", "classpath:/config/https.xml");

WebClient client = WebClient.create("http://books", "username", "password", "classpath:/config/https.xml");

When injecting clients from Spring, one can add 'username' and 'password' values as attributes to jaxrs:client elements or add them to WebClient factory create methods.

Clients in Spring Boot

Please see JAXRSClientSpringBoot documentation on how CXF JAX-RS Clients can be used in a SpringBoot Application.

Clients and HTTP(s)

The default HttpClientHTTPConduit conduit by default supports the following HTTPS protocols: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3. Since Apache CXF 4.0.4 / 3.6.3 release, the default HttpClientHTTPConduit respects https.protocols system property (see please https://blogs.oracle.com/java/post/diagnosing-tls-ssl-and-https) and if set, would use the provided protocols. This behavior could be turned off by setting https.protocols.ignored system property to "true" (the default value is "false").