Versions Compared

Key

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

CXF has an initial implementation of supports JAX-RS (JSR-311): , Java API for RESTfulWeb RESTful Web Services. JAX-RS provides a more standard way to build RESTful services in Java. CXF 2.2 supports the final version of JSR-311 API while CXF 2.1 currently supports only 0.8 version of JSR-311 API is currently supported.

JAX-RS related demos are located under samples\/jax_rs directory (CXF 2.2 and CXF 2.1 only).
This documentation will refer to JSR-311 API 1.0 .

Understanding the basics

You are encouraged to read JAX-RS spec to find out information not covered by this documentation.

...

Code Block
java
java
package demo.jaxrs.server;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.ProduceMimeProduces;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

@Path("/customerservice/")
@ProduceMime("application/xml")
public class CustomerService {

    public CustomerService() {
    }

    @GET
    public Customers getCustomers() {
        ......
    }

    @GET
    @Path("/customers/{id}")
    @ProduceMime@Produces("application/json")
    public Customer getCustomer(@PathParam("id") String id) {
        ......
    }

    @PUT
    @Path("/customers/{id}")
    @ConsumeMime@Consumes("application/xml")
    public Response updateCustomer(@PathParam("id") Long id, Customer customer) {
        ......
    }

    @POST
    @Path("/customers")
    public Response addCustomer(Customer customer) {
        ......
    }

    @DELETE
    @Path("/customers/{id}/")
    public Response deleteCustomer(@PathParam("id") String id) {
        ......
    }

    @Path("/orders/{orderId}/")
    public Order getOrder(@PathParam("orderId") String orderId) {
       ......
    }
}

...

JAX-RS relies on MessageBodyReader and MessageBodyWriter implementations to serialize and de-serialize Java types. JAX-RS requires that certain types has to be supported out of the box.
By default, CXF supports String, byte[], InputStream, Reader, File, JAXP Source, JAX-RS StreamingOutput, JAXB-annotated types with application/xml and application/json formats as well as JAXBElement (see below). JAX-RS MultivaluedMap is also supported for form contents.

Custom Message Body Providers

It's likely that a given application may need to deal with types which are not supported by default.
Alternatively, developers may want to provide a more efficient support for handling default types such as InputStream.

Here's an example of a custom MessageBodyReader for InputStream :

JSON support

Default JSON provider relies on Jettison 1.0.1 and it expects the types it deals with to follow the same techniques as described above
in the JAXB support section for them to be handled properly.

Following code returns a Customer object that is marshaled to JSON format:

Code Block

@Path("/customerservice/")
public class CustomerService {
    @ProduceMime("application/json")
    @GET
    @Path("/customers/{customerId}/")
    public Customer getCustomer(@PathParam("customerId") String id
Code Block
javajava


@ConsumeMime("application/octet-stream")
@Provider
public class InputStreamProvider implements MessageBodyReader<InputStream> {

    
    public boolean isReadable(Class<InputStream> type, Type genericType, Annotation[] annotations) {
        return InputStream...class.isAssignableFrom(type);
    }

The wire representation of Customer object is:

Code Block
java
java
{"Customer ":{"id":"123","name":"john"}}

Source support

You can also receive the request as a Source object or return a Source object as response:

Code Block
java
java

@Path("/customerservice/")
public class CustomerService {    public InputStream readFrom(Class<InputStream> clazz, Type t, Annotation[] a, MediaType mt, 
    @PUT
    @Path("/customers/")
    public javax.xml.transform.Source updateCustomer(javax.xml.transform.Source ds) {
        ....
    }
}

Custom Message Body Providers

It's likely that a given application may need to deal with types which are not supported by default.
Alternatively, developers may want to provide a more efficient support for handling default types such as InputStream.

Here's an example of a custom MessageBodyReader for InputStream :

Code Block
java
java


@Consumes("application/octet-stream")
@Provider
public class InputStreamProvider implements MessageBodyReader<InputStream> {

     MultivaluedMap<String, String> headers, InputStream is) 
        throws IOException {
    public boolean isReadable(Class<InputStream> type, Type genericType, Annotation[] returnannotations, newMediaType FilterInputStream(ismt) {
        return InputStream.class.isAssignableFrom(type);
    @Override}

    public InputStream readFrom(Class<InputStream> clazz, Type     public int read(bytet, Annotation[] b)a, throwsMediaType IOExceptionmt, {
                 // filter out some bytes
    MultivaluedMap<String, String> headers, InputStream is) 
    }    throws IOException {
        return new FilterInputStream(is) {
        }     @Override
    }
}

and here's an example of a custom MessageBodyWriter for Long :

Code Block
javajava


@ProduceMime("text/plain")
@Provider
public class LongProvider implements MessageBodyWriter<Long> {

    public longint getSizeread(Longbyte[] lb) throws IOException {
        return -1;
    }

    public// boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations) {filter out some bytes
        return long.class.isAssignableFrom(type) || Long.class.isAssignableFrom(type);
    }

    public void writeTo(Long l, Class<?> clazz, Type type, Annotation[] a, 
        }     
    }
}

and here's an example of a custom MessageBodyWriter for Long :

Code Block
java
java


@ProduceMime("text/plain")
@Provider
public class LongProvider implements MessageBodyWriter<Long> {
       MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) 
        throws IOException {
    public long getSize(Long  os.write(l.toString().getBytes());l, Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {
        return -1;
    }

CXF ships some custom providers too. These are providers for dealing with Atom (based on Apache Abdera) and XMLObjects.
CXF also supports primitive types and their Number friends when text/plain media type is used, either on input or output.

Registering custom providers

Putting @Provider annotation on the provider class is something that should lead to your provider being registered with the runtime. CXF does not support this feature yet.

One can easily register a provider either from the Spring configuration or programmatically :

Code Block
xmlxml


<beans>
<jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <bean class="org.CustomerService" />
    </jaxrs:serviceBeans>

    <jaxrs:providers>
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {
        return long.class.isAssignableFrom(type) || Long.class.isAssignableFrom(type);
    }

    public void writeTo(Long l, Class<?> clazz, Type type, Annotation[] a, 
                   <ref bean="isProvider" />
   MediaType mt,  <ref bean="longProvider" />MultivaluedMap<String, Object> headers, OutputStream os) 
    </jaxrs:providers>
    <bean id="isProvider" class="com.bar.providers.InputStreamProvider"/>
throws IOException {
     <bean id="longProvider" class="com.bar.providers.LongProvider"/>
</jaxrs:server>
</beans>

Note that instead of the older <jaxrs:entityProviders> it's now <jaxrs:providers>. JAX-RS supports different types of providers and having a single <jaxrs:providers> container is in line with the way other JAX-RS implementations discover providers by checking for @Provider annotations only.

See below a more complete beans.xml definition.

While having @Provider-annotated providers automatically registered is a handy feature indeed, sometimes it might actually be problematic.
For ex, in a large project user providers from different libraries might clash. Also, with a custom configuration (as shown above) a different type of provider (handling the same format of request/response bodies) can be registered with a different jaxrs:server instance.

Content type negotiation

One of the coolest thing of REST is that the same resource can be served using multiple representations. @ProduceMime and @ConsumeMime annotations are used to declare the supported request and response media types.

JAXB support

The request and response can be marshalled and unmarshalled to/from Java object using JAXB.

There's a number of ways to tell to the JAXB provider how objects can be serialized. The simplest way is to mark a given type with @XmlRootElement annotation.

For example:

  os.write(l.toString().getBytes());
        
    }

CXF ships some custom providers too. These are providers for dealing with Atom (based on Apache Abdera) and XMLObjects.
CXF also supports primitive types and their Number friends when text/plain media type is used, either on input or output.

Registering custom providers

Putting @Provider annotation on the provider class is something that should lead to your provider being registered with the runtime. CXF does not support this feature yet.

One can easily register a provider either from the Spring configuration or programmatically :

Code Block
xml
xml


<beans>
<jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <bean class="org.CustomerService" />
    </jaxrs:serviceBeans>

    <jaxrs:providers>
      <ref bean="isProvider" />
Code Block
javajava

@XmlRootElement(name = "Customer")
public class Customer {
    private String name;
    private long id;

    public Customer() {
    }

    public void setName(String n) {
      <ref  name = n;bean="longProvider" />
    }
</jaxrs:providers>
    public String getName() {<bean id="isProvider" class="com.bar.providers.InputStreamProvider"/>
        return name;
    }

    public void setId(long i) {
        id = i;
    }

    public long getId() {
        return id;
    }
}

In the example below, the Customer object returned by getCustomer is marshaled using JAXB data binding:

<bean id="longProvider" class="com.bar.providers.LongProvider"/>
</jaxrs:server>
</beans>

Note that instead of the older <jaxrs:entityProviders> it's now <jaxrs:providers>. JAX-RS supports different types of providers and having a single <jaxrs:providers> container is in line with the way other JAX-RS implementations discover providers by checking for @Provider annotations only.

See below a more complete beans.xml definition.

While having @Provider-annotated providers automatically registered is a handy feature indeed, sometimes it might actually be problematic.
For ex, in a large project user providers from different libraries might clash. Also, with a custom configuration (as shown above) a different type of provider (handling the same format of request/response bodies) can be registered with a different jaxrs:server instance.

Support for data bindings

JAXB support

The request and response can be marshalled and unmarshalled to/from Java object using JAXB.

There's a number of ways to tell to the JAXB provider how objects can be serialized. The simplest way is to mark a given type with @XmlRootElement annotation.

For example:

Code Block
java
java

@XmlRootElement(name = "Customer")
public class Customer
Code Block
javajava

@Path("/customerservice/")
public class CustomerService {
    @GET
    @Path("/customers/{customerId}/")
    public Customer getCustomer(@PathParam("customerId") String id) {
    private String   ....name;
    private long id;

    }
}

The wire representation of Customer object is:

Code Block
javajava

@Path("/customerservice/")
<Customer>
    <id>123</id> public Customer() {
    }

    public void setName(String n) {
        name = n;
    <name>John</name>
</Customer>

The simplest way to work with the collections is to define a type representing a collection. For example:

Code Block

@XmlRootElement(name = "Customers")
public class Customers {
}

    public String getName() {
       private Collection<Customer>return customersname;
    }

    public Collection<Customer>void getCustomersetId(long i) {
        id return= customersi;
    }

    public voidlong setCustomergetId(Collection<Customer> c) {
        this.customers = creturn id;
    }
}
@Path("/customerservice/")

In the example below, the Customer object returned by getCustomer is marshaled using JAXB data binding:

Code Block
java
java

@Path("/customerservice/")
public class CustomerService {
    @GET
    @Path("/customers/{customerId}/")
    public CustomersCustomer getCustomers(getCustomer(@PathParam("customerId") String id) {
        ....
    }
}

Alternatively to using @XmlRootElement and Collection wrappers, one can provide an Object factory which will tell JAXB how to
marshal a given type (in case of Collections - its template type). Another option is to return/accept a JAXBElement directly from/in
a given method.

Another option is to register one or more JAX-RS ContextResolver providers capable of creating JAXBContexts for a number of different types. The default JAXBElementProvider will check these resolvers first before attempting to create a JAXBContext on its own.

Finally, JAXBProvider provides an experimental support for marshalling response types of methods annotated with @XmlJavaTypeAdapter annotations.
It's likely that at some point of time JAX-RS runtime will be capable of automatically generating such adapters.

JSON support

Default JSON provider relies on Jettison 1.0.1 and it expects the types it deals with to follow the same techniques as described above
in the JAXB support section for them to be handled properly.

Following code returns a Customer object that is marshaled to JSON format:

The wire representation of Customer object is:

Code Block
java
java

@Path("/customerservice/")
<Customer>
    <id>123</id>
    <name>John</name>
</Customer>

The simplest way to work with the collections is to define a type representing a collection. For example:

Code Block

@XmlRootElement(name = "Customers
Code Block

@Path("/customerservice/")
public class CustomerServiceCustomers {
    private Collection<Customer> customers;

    @ProduceMime("application/json")public Collection<Customer> getCustomer() {
    @GET
    @Path("/customers/{customerId}/")return customers;
    }

    public Customervoid getCustomer(@PathParam("customerId") String idsetCustomer(Collection<Customer> c) {
        this....
customers =   }

The wire representation of Customer object is:

...


{"Customer ":{"id":"123","name":"john"}}

Source support

You can also receive the request as a Source object or return a Source object as response:

Code Block
javajava
c;
    }
}
@Path("/customerservice/")
public class CustomerService {
    @GET
    @PUT
    @Path("/customers/")
    public javax.xml.transform.Source updateCustomer(javax.xml.transform.Source ds) {
        ....
    }
}
@Path("/customers/")
    public Customers getCustomers() {
        ....
    }
}

Alternatively to using @XmlRootElement and Collection wrappers, one can provide an Object factory which will tell JAXB how to
marshal a given type (in case of Collections - its template type). Another option is to return/accept a JAXBElement directly from/in
a given method.

Another option is to register one or more JAX-RS ContextResolver providers capable of creating JAXBContexts for a number of different types. The default JAXBElementProvider will check these resolvers first before attempting to create a JAXBContext on its own.

Finally, JAXBProvider provides an experimental support for marshalling response types of methods annotated with @XmlJavaTypeAdapter annotations.
It's likely that at some point of time JAX-RS runtime will be capable of automatically generating such adapters.

Content type negotiation

One of the coolest thing of REST is that the same resource can be served using multiple representations. @Produces and @Consumes annotations are used to declare the supported request and response media types.

TODO : more content here

Debugging

One can easily try from a browser how a given resource class reacts to different HTTP Accept or Accept-Language header values.
For example, if a resource class supports "/resource" URI then one can test the resource class using one of the following
queries :

...

A demo called samples\jax_rs\basic_https shows you how to do communications using HTTPS.

TODO : do SpringSecurity demo

Configuring JAX-RS services

...

Code Block
java
java
@Path("/customers/{a}")
public class CustomerService {
   void doIt(@PathParam("a") String a, String b) {...};
}

For methods returning 'void', a simple custom provider can be created which will basically be a no-op implementation.

JAX-RS and Spring AOP

CXF JAX-RS is capable of working with AOP interceptors applied to resource classes from Spring.
For example :

...

Code Block
java
java

public interface BookInterface {
    @GET
    @Path("/thosebooks/{bookId}/")
    @ProduceMime@Produces("application/xml")
    Book getThatBook(Long id) throws BookNotFoundFault;
}

public class BookStoreWithInterface extends BookStoreStorage implements BookInterface {

    public Book getThatBook(@PathParam("bookId") Long id) throws BookNotFoundFault {
        return doGetBook(id);
    }

    @Path("/thebook")
    public Book getTheBook(@PathParam("bookId") Long id) throws BookNotFoundFault {
        return doGetBook(id);
    }
}

...

Complete the implementation of JAX-RS UriInfo (latest methods to do with the ancestor resources) and in particularly of UriBuilder
Complete the implementation of JAX-RS Request (If-Modified-Since, Vary) and ResponseBuilder(Vary)
Support Constructor-based injection
Support javax.activation.DataSource out of the box
ASM-generate XmlJavaTypeAdapters when needed
Provide AegisBindingProvider
Provide JAXP-Source provider capable of applying preconfigured XSLT templates or XPath expressions
Proper HTTP status handling in various cases as per the spec
Support of @Encoded on a method (class and parameter targets supported)
Support of encoded @Path values
Support for inheritance of @PathParam and @Context annotations from interface/superclass methods
Create some useful request filter implementations : JavaScript code generation, WADL or JavaDocs generation
Investigate the possibility of creating a client-side api using JAXRSClientFactory
Support FormParam, GenericEntity