Search This Blog

Friday, August 8, 2008

JAXRS, JBoss RestEasy, Maven, Spring...rock on!

I'm drowning my audience with Rest related code. What can I do, the hunger is biting me bad! JSR 311/JAXRS is an API. Different providers provide their own implementations of the same. I have already explored RESTLET's version of the implementation and how it applies to my SpringRestlet example. Note the common theme running here..I need a framework to be able to provide a Spring Hook otherwise, I turn my head the other way :-). Yeah, a Spring fan (those who remember the movie "Swim fan" feel my obsession)!

That said, we move on to the example. RestEasy is a JBoss project that allows one to build RESTful webservices. I like their philosophy where they say, the goal is to build an easy way to speak REST.

As of this blog, Rest Easy JAXRS is at : 1.0 BETA 5. Some of the things I liked about the implementation right away:

1. Support for a Client API to talk to Restful Webservice
2. Easy Spring Integration
3. Maven Support
4. Decent Documentation
5. Easy to get going with a Starter Webservice
6. JBoss Backing..we have Hibernate after all ;-)
7. Last but not the least led by a member of the JSR

In my previous blog with the RESTLET framework support for JAXRS and Spring I had developed my own custom Servlet. With Rest Easy, I did not have to do the same. My webapp's web.xml has exactly the same configuration as mentioned in the RestEasy documentation. One major issue that I encountered is that I could not get auto discovery of Spring managed Resources and Providers (as advertised by the framework) without annotating the corresponding classes with the Spring @Component annotation. Maybe there is something I am missing. Regardless, I have filed a bug report with the RestEasy jira, lets see what surfaces from the same.

With the Resteasy version of my Spring/Restlet example , the webapp module has only 3 classes! An OrderNotFoundProvider class that translates all OrderNotFoundExceptions to meaningful REST responses, an OrderResource and a ProductsResource. I do not have any other JAVA artifacts in this module. A provider class for the Products that managed the marshalling specifics (
JSON marshalling/unmarshalling) has been moved to the common maven module to be shared among client and web modules. Regardless, look at my webapp module now, all we have is Resource and Exception management classes :-). Gone are the Application, Servlet, ApplicationConfig ...etc etc classes.

Unlike in the previous example of JAXRS that I had provided, in this example, I have changed the Client to use RestEasy's JAXRS Client support. I must admit, I am rather impressed by their effort with the same. So what are the changed in the client, the OrderClient has changed to:
@ConsumeMime("application/xml") 
public interface OrderClient {

/**
* Create an Order.
*
* @param orderDTO Order DTO
* @return OrderDTO with created id
* @throws IOException If an error occurs
*/

@POST
@Path("/order")
@ProduceMime("application/xml")
@ConsumeMime("application/xml")
public OrderDTO createOrder(OrderDTO orderDTO) throws IOException;

/**
* Updates an Order.
*
* @param orderDTO Order DTO
*/

@PUT
@Path("/order/{id}")
@ProduceMime("application/xml")
public void updateOrder(OrderDTO orderDTO, @PathParam ("id") Long id);

/**
* Retrieves an Order with the specified <code>orderId</code>.
*
* @param orderId Order Id
* @return OrderDTO
* @throws OrderNotFoundException if order is not found
* @throws IOException if an error occurs
*/

@GET
@Path("/order/{id}")
@ProduceMime("application/xml")
public OrderDTO getOrder(@PathParam("id") Long orderId) throws OrderNotFoundEx
ception, IOException;

/**
* Deletes an Order with the specified <code>orderId</code>
*
* @param orderId order Id
* @throws OrderException If an error occurs
*/

@DELETE
@Path("/order/{id}")
@ProduceMime("application/xml")
public void deleteOrder(@PathParam("id") Long orderId) throws OrderException;
}


Note the use of JAXRS annotations in the Order Client. Code is being shared, always a good thing :-). It is sufficient with the OrderClient defintion to talk to the webservice using Reseasy code. The same can be accomplished with the following lines from a consumer:

ResteasyProviderFactory.initializeInstance(); 
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

OrderClient client = ProxyFactory.create(OrderClient.class, "http://localhost:9090/IntegrationTest");

The first two lines initialize the Resteasy client code. The third line is where a Proxy is created for the OrderClient. In the spirit of my rest/spring example, I have decided to provide an abstraction where I delegate to the proxy mentioned above as shown below ;-) :
public class OrderClientImpl implements OrderClient { 
private final OrderClient delegate;

/**
* @param uri Server Uri
*/

public OrderClientImpl(String uri) {
delegate = ProxyFactory.create(OrderClient.class, uri);
}

public OrderDTO createOrder(OrderDTO orderDTO) throws IOException {
return delegate.createOrder(orderDTO);
}

public void deleteOrder(Long orderId) throws OrderException {
delegate.deleteOrder(orderId);
}

public OrderDTO getOrder(Long orderId) throws OrderNotFoundException, IOExcept
ion {
return delegate.getOrder(orderId);
}

public void updateOrder(OrderDTO orderDTO, Long id) {
delegate.updateOrder(orderDTO, id);
}

}

I choose to depend on my Integration test and/or consumer of the service to initialize the Resteasy framework via plugins/listener what have you.

Above said, the code just works nice. I feel with the Resteasy JAXRS implementation, I have reduced the amount of coding required to build REST web service that integrates with my favorite framework Spring. Onward and upward you Resteasy folks!

The Resteasy version of the JAXRS Spring/RestEasy/Maven/Dozer project can be downloaded from HERE!
The example was run using JDK 1.6.X and Apache maven 2.0.9 on Linux environment.
Enjoy! I am off to look at CXF from the apache foundation next..:-) ...

3 comments:

Donny said...

Thanks for great example on setting up a REST client!!

Sanjay Acharya said...

Thanks much.

Anonymous said...

thanks for the post. it was helpful for me