Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
CXF has an initial implementation of JAX-RS (JSR-311): Java API for RESTfulWeb Services. JAX-RS provides a more standard way to build RESTful services in Java.

...



JAX-RS related demos are located under samples\jax_rs directory (CXF 2.1 only).

h1.

...

 Understanding the basics

...



You are encouraged to read [JAX-RS

...

Resource class

A resource class is a Java Class annotated with JAX-RS annotations to represent a Web resource. A typical resource class in JAX-RS looks like below:

Code Block
javajava
 spec | http://jcp.org/en/jsr/detail?id=311] to find out information not covered by this documentation.

h2. Resource class

A resource class is a Java Class annotated with JAX-RS annotations to represent a Web resource. A typical resource class in JAX-RS looks like below:
{code:java}
package demo.jaxrs.server;

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

import javax.ws.rs.GET;
import javax.ws.rs.ProduceMime;
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/")
public class CustomerService {

    public CustomerService() {
    }

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

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

    @PUT
    @Path("/customers/{id}")
    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) {
       ......
    }
}

@Path

@Path annotation is applied to resource classes or methods. The value of @Path annotation is a relative URI path follows the URI Template format.

More information about Path annotations can be found from JAX-RS spec section 2.3.

HTTP Method

JAX-RS specification defines a number of annotations such as @GET, @PUT, @POST and @DELETE. Using an @HttpMethod designator, one can create a custom annotation such as @Update or @Patch

Sub-resource locators.

A method of a resource class that is annotated with @Path becomes a sub-resource locator when an annotation with an @HttpMethod designator is not present. Sub-resource locators are used to further resolve the object that will handle the request. In the example below, getOrder method is a sub-resource locator:

Code Block
javajava

@Path("/customerservice/")
public class CustomerService {

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

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

    public Order() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String d) {
        this.description = d;
    }

    @GET{code}

Customer resource class can handle requests starting from /customerservice. When /customerservice request is matched to this class, its getCustomers() method will be selected. updateCustomer(), deleteCustomer() and addCustomer() are used to serve POST, PUT and DELETE requests starting from /customerservice/customer, while getOrder() method delegates the handling of /customerservice/orders/{orderId} to a subresource locator Order.

h2. @Path

@Path annotation is applied to resource classes or methods. The value of @Path annotation is a relative URI path follows the URI Template format. 

More information about Path annotations can be found from [JAX-RS spec | http://jcp.org/en/jsr/detail?id=311] section 2.3. 

h2. HTTP Method

JAX-RS specification defines a number of annotations such as @GET, @PUT, @POST and @DELETE. Using an @HttpMethod designator, one can create a custom annotation such as @Update or @Patch

h2. Return types

Either javax.ws.rs.core.Response or custom type can be returned. javax.ws.rs.core.Response can be used to set the HTTP response code, headers and entity. 

h3. Exception handling

One can either throw an unchecked WebApplicationException or return Response with a proper error code set.
The former option may be a better option when no JAX-RS types can be added to method signatures.

For example :

@Path("/customerservice/")
public class CustomerService {

    
    @PUT
    @Path("products/customers/{productIdid}/")
    public ProductResponse getProductupdateCustomer(@PathParam("productIdid")int productId Long id, Customer customer) {
        return Response......status(errorCode).build();
    }

}

A HTTP GET request to http://localhost:9000/customerservice/orders/223/products/323 is dispatched to getOrder method first. If the Order resource whose id is 223 is found, the Order 223 will be used to further resolve Product resource. Eventually, a Product 323 that belongs to Order 223 is returned.

Message Body Providers

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, File, JAXP Source, JAXB-annotated types with application/xml and application/json formats (see below). JAX-RS MultivaluedMap is also supported for
form contents. Support for other types like Reader and StreamingOutput is on the way.

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 (0.7 jax-rs api) :

Code Block
javajava


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

    
    public boolean isReadable(Class<InputStream> type, Type genericType, Annotation[] annotations) {    @POST
    @Path("/customers")
    public Customer addCustomer(Customer customer) {
        throw new WebApplicationException(errorCode);
    }

}
{code}

h2. Annotation inheritance

Most of the JAX-RS annotations can be inherited from either an interface or a superclass. JAX-RS specification requires that only the ones applied to methods can be inherited. For example :

{code:java}

public interface CustomerService {

    @PUT
    @Path("/customers/{id}")
    Response updateCustomer(Long id, Customer customer) {
        return Response.status(errorCode).build();
    }

    @POST
    @Path("/customers")
    Customer addCustomer(Customer customer) {
        throw new WebApplicationException(errorCode);
    }

}
{code}


@Path("/customerservice/")
public class Customers implements CustomerService {

    
    public Response updateCustomer(@PathParam("id"), Customer customer) {
        return Response.status(errorCode).build();
    }

    public Customer addCustomer(Customer customer) {
        throw new WebApplicationException(errorCode);
    }

}
{code}

Note that annotations applied to the interface are inherited. CXF is not capable yet of inheriting the annotations applied to parameters such as @PathParam so at the moment they need to be specified anyway at the root class level. 

Similarly annotations can be inherited from super-classes. 

CXF can inherit annotations applied directly to super-classes such as  @Path("/customerservice/") which is applied to the Customers class above. It may support the same type of inheritance for interfaces too. Note this is not JAX-RS compliant.  


h2. Sub-resource locators.

A method of a resource class that is annotated with @Path becomes a sub-resource locator when an annotation with an HttpMethod designator like @GET is not present. Sub-resource locators are used to further resolve the object that will handle the request. They can delegate to other sub-resource locators. In the example below, getOrder method is a sub-resource locator:
{code:java}
@Path("/customerservice/")
public class CustomerService {

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

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

    public Order() {
    }

    public long getId() {
        return id;
    }


    @GET
    @Path("products/{productId}/")
    public Product getProduct(@PathParam("productId")int productId) {
       ......
    }
}
{code}
A HTTP GET request to [http://localhost:9000/customerservice/orders/223/products/323] is dispatched to getOrder method first. If the Order resource whose id is 223 is found, the Order 223 will be used to further resolve Product resource. Eventually, a Product 323 that belongs to Order 223 is returned.

h2. Message Body Providers

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, File, JAXP Source, JAXB-annotated types with application/xml and application/json formats (see below). JAX-RS MultivaluedMap is also supported for
form contents. Support for other types like Reader and StreamingOutput is on the way.


h2. 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 (0.7 jax-rs api) :

{code:java}

@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);
    }

    public InputStream readFrom(Class<InputStream> clazz, Type t, MediaType mt, 
                         Annotation[] a, MultivaluedMap<String, String> headers, InputStream is) 
        throws IOException {
        return new FilterInputStream(is) {
             @Override
             public int read(byte[] b) throws IOException {
                 // filter out some bytes
        return InputStream.class.isAssignableFrom(type);
    }

              
    public InputStream readFrom(Class<InputStream> clazz, Type t, MediaType mt, 
   }     
    }
}

{code}

and here's an example of a custom MessageBodyWriter for Long (0.7 jax-rs api) :

{code:java}

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

 Annotation[] a, MultivaluedMap<String, String>public headers, InputStream islong getSize(Long l) {
        return -1;
  throws IOException {}

    public boolean isWriteable(Class<?> type, Type return new FilterInputStream(isgenericType, Annotation[] annotations) {
        return long.class.isAssignableFrom(type)    @Override
|| Long.class.isAssignableFrom(type);
    }

    public void writeTo(Long l, Class<?> clazz, publicType int read(bytetype, Annotation[] b)a, throws
 IOException {
                 // filter out some bytes
 MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) 
     }   throws IOException {
         os.write(l.toString().getBytes());
        }     
    }

{code}

and here's an example of a custom MessageBodyWriter for Long (0.7 jax-rs api) :

Code Block
javajava


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

    public long getSize(Long l) {
        return -1;
    }

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

    public void writeTo(Long l, Class<?> clazz, Type type, Annotation[] a, h3. 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 :   

{code:xml}

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

    <jaxrs:entityProviders>
      <bean  MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) ref="isProvider" />
      <bean ref="longProvider" />
    </jaxrs:entityProviders>
    throws IOException {<bean id="isProvider" class="com.bar.providers.InputStreamProvider"/>
    <bean    os.write(l.toString().getBytes());
        
    }

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 :

...



<beans>
<jaxrs:server id="customerService" address="/">
    <jaxrs:entityProviders>
      <bean ref="isProvider" />
      <bean ref="longProvider" />
    </jaxrs:entityProviders>
    <bean id="isProvider" class="com.bar.providers.InputStreamProvider"/>
    <bean id="longProvider" class="com.bar.providers.LongProvider"/>
</jaxrs:server>
</beans>


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 marshaled and unmarshaled to/from Java object using JAXB. The Java object needs to be marked with @XmlRootElement annotation. For example:

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

Please note that once CXF is updated to support a 0.7 version of JAX-RS api, <jaxrs:entityProviders> will be changed to <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.

{code}

h2. 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. 


h3. JAXB support

The request and response can be marshaled and unmarshaled to/from Java object using JAXB. The Java object needs to be marked with @XmlRootElement annotation. For example:
{code:java}
@XmlRootElement(name = "Customer")
public class Customer {
    private String name;
    private long id;

    public Customer() {
    }

    public void setName(String n) {
        name = n;
    }

    public String getName() {
        return name;
    }

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

    public long getId() {
        return id;
    }

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

...


{code
:java
java
}
@Path("/customerservice/")
public class CustomerService {
    @GET
    @Path("/customers/{customerId}/")
    public Customer getCustomer(@PathParam("customerId") String id) {
        ....
    }
}
{code}
The wire representation of Customer object is:

...

Code Block
javajava

{code:java}
@Path("/customerservice/")
<Customer>
    <id>123</id>
    <name>John</name>
</Customer>
{code}

To work with collections, you need to define an object collection type. For example:

...


{code
}
@XmlRootElement(name = "Customers")
public class Customers {
    private Collection<Customer> customers;

    public Collection<Customer> getCustomer() {
        return customers;
    }

    public void setCustomer(Collection<Customer> c) {
        this.customers = c;
    }
}
@Path("/customerservice/")
public class CustomerService {
    @GET
    @Path("/customers/")
    public Customers getCustomers() {
        ....
    }
}

JSON support

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

Code Block
{code}

h3. JSON support

Following code returns a Customer object that is marshaled to JSON format:
{code}
@Path("/customerservice/")
public class CustomerService {
    @ProduceMime("application/json")
    @GET
    @Path("/customers/{customerId}/")
    public Customer getCustomer(@PathParam("customerId") String id) {
        ....
    }
{code}

The wire representation of Customer object is

...

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

h3. Source support

...



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

...



{code
:java
java
}
@Path("/customerservice/")
public class CustomerService {
    @PUT
    @Path("/customers/")
    public javax.xml.transform.Source updateCustomer(javax.xml.transform.Source ds) {
        ....
    }
}

...

{code}

h2. Secure JAX-RS services

...



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

...



h1. Configuring JAX-RS

...

Configuring JAX-RS services programmatically

...

 services


h2. Configuring JAX-RS services programmatically

You can create a JAX-RS RESTful service by using [JAXRSServerFactoryBean|http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java?view=markup&pathrev=HEAD] from the _cxf-rt-frontend-jaxrs_ package:

...

 
{code
:java
java
}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(CustomerService.class);
sf.setAddress("http://localhost:9000/");
sf.create();
{code}
A couple things to note:

...


* The JAXRSServerFactoryBean creates a Server inside CXF which starts listening for requests on the URL specified.

...


* By default, the JAX-RS runtime is responsible for the lifecycle of resource classes, default lifecycle is per-request. You can set the lifecycle to singleton by using following line:

...


{code

...

:java

...

}
sf.setResourceProvider(BookStore.class, new SingletonResourceProvider());

...

{code}
* If you prefer not to let the JAX-RS runtime to handle the resource class lifecycle for you (for example, it might be the case that your resource class is created by other containers such as Spring), you can do following:

...


{code

...

:java

...

}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
CustomerService cs = new CustomerService();
sf.setServiceBeans(cs);
sf.setAddress("http://localhost:9080/");
sf.create();

...

{code}

h2. Configuring JAX-RS services in container with Spring configuration file.

...




h3. web.xml

...

Code Block
xmlxml


{code:xml}
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>WEB-INF/beans.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<servlet>
		<servlet-name>CXFServlet</servlet-name>
		<display-name>CXF Servlet</display-name>
		<servlet-class>
			org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>CXFServlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>
{code}

h3. beans.xml

...



{code
:xml
xml
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jaxrs="http://cxf.apache.org/jaxrs"
  xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">

  <import resource="classpath:META-INF/cxf/cxf.xml" />
  <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

  <jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <bean classref="demo.jaxrs.server.CustomerServicecustomerService" />
    </jaxrs:serviceBeans>
  </jaxrs:server>

  <bean id="customerService" class="demo.jaxrs.server.CustomerService" />
</beans>

...

{code}


h2. Areas for improvement and TODO list.