RESTEasy Preview: A RESTful Web Services Framework for Java

For the past few months, I have been mucking around with an idea for a RESTful Web Services framework I call RESTEasy. The project was inspired by the JAX-WS API and some of the work done by the WADL project. Yesterday, I noticed this post on Marc Hadley’s Blog regarding JSR-311. I thought I’d share what I’ve been up to, since some of my ideas in RESTEasy are quite similar.

My driver for RESTEasy was to make it very transparent to expose a SessionBean or a POJO as a RESTful service and using JAXB annoated Entity Beans as value objects. I had looked into the RESTful capabilities of JAX-WS, but it is not quite a complete solution yet. I wanted a RESTful framework to do the following:

  • Seamless integration with EJB3 SessionBeans, Message Driven Beans, POJOs, JPA/Hibernate, and JAXB
  • Annotation based
  • Automatically discover class marked with an @WebReource annotation
  • Route HTTP method to the proper Java method for the specified URI

A simple RESTful SessionBean service in RESTEasy look like this:

 
@Stateless
@WebResource("/contacts/{contactId}")
public class ContactServiceBean implements ContactService { 


@PersistenceContext
private EntityManager entityManager;

@HttpMethod("GET")
public Contact getContactById(@URLParam("contactId") Long contactId) {
    Contact contact = entityManager.find(Contact.class, contactId);
    return contact;
  }

@HttpMethod("POST")
public Contact updateContact(@Representation("contact") Contact contact) {
    return entityManager.merge(contact);
  }
}

By default, RESTEasy uses JAXB to convert XML documents to Java Objects and back. However, RESTEasy is not limited to just XML-based reources and can work with most media types through the RepresentationHandler interface. In the example above, the Contact class is managed by Hibernate and JAXB. When a GET request is issued for the following URL:


http://somehost/contacts/12345

RESTEasy will extract the contactId from the URL and converted to a Long and the getContactById() methdod invoked. The return value is automagically marshalled to XML and returned to the client.

A POST operation to the same URL will invoke the updateContact() method. In this case, the parameter marked with the @Representation is unmarshalled to our Contact class by JAXB and the updateContact() method is invoked.

If you want to combine multiple URIs to a single class or EJB, you can use the @WebResources annotation to group multipe @WebReource annotations:

@Stateless
@WebResources(
  resources={@WebResource(id=ContactService.CONTACT_BASE,value="/contacts"),
             @WebResource(id=ContactService.INDIVIDUAL,value="/contacts/{contactId}")}
)

public class ContactServiceBean implements ContactService { 

When using the the @WebResources annotation, each @WebReource must define an unique ID. This ID is then referenced by each @HttpMethod annotation using the resourceId attribute:


@HttpMethod(value=HttpMethod.POST, resourceId=ContactService.INDIVIDUAL)

Since some HTTP clients such as Apple’s Safari and Adobe Flash don’t support the DELETE and PUT http methods, you’ll be limited to using only GET and POST operations. If it’s important for you to be able to use PUT where the client supports put but also be able to handle a client that does not support PUT, you can do the following:


@HttpMethods(methods={
    @HttpMethod(resourceId=ContactService.CONTACT_BASE,value=HttpMethod.PUT),
    @HttpMethod(resourceId=ContactService.CONTACT_BASE,value=HttpMethod.POST,discriminator="create")
})
public void createContact(@Representation("contact") Contact contact);

The discriminator value is used to distinguish multiple POST operations for same URL. If you define the discriminator name to be “Action”, RESTEasy would write the create URL for a contact as:


http://somehost/contacts?Action=create

And a DELETE operation using POST could be:


http://somehost/contacts/12345?Action=delete

Right now, I have RESTEasy working very well with the RESTEasy client. I am also using to delevlop an Adobe FLEX based application which is working better than expected. There’s still a bit of work left to do on RESTEasy before the code get released into the wild. Here’s what I need to do at the moment:

  • Decide on a place to host the project (java.net, Source Forge, or Google Code)
  • Need to do some more thinking about how to handle some HTTP headers such as created, last modified, Content-Length, etc. As of now, these values aren’t supported
  • JPA/Hibernate integration is a big part of RESTEasy. One of the challenges of using RESTEasy with a SessionBean is that the ResourceInvoker, the class that routes and HTTP method to a Java Method, resides on teh web tier. In order to avoid LazyInitializationException, the EJBResourceInvoker can start a UserTransaction before the EJB is invoked. This ensures that everything goes as planned when marshalling the JAXB annotated Entity to XML. JBoss Seam appears handle this rather well for JSF applications. I’m looking to see if there is a way to utilize Seam’s remoting package to achcive what I am doing in the dispatch servlet. Or prehaps there is a better way to manage this all together.
  • Implement conditional gets to minimize load on the server.
  • Finish the documentation
  • Service stub generation from a WADL definition

There is also a RESTEasy client that I’ll cover in another post

Advertisement

8 thoughts on “RESTEasy Preview: A RESTful Web Services Framework for Java

  1. Have you guys implemented support for including public key signature in http header for RestEasy, same way as WSSE inserts on SOAP header?

    Like

  2. Have you guys implemented support for including public key signature in http header for RestEasy, same way as WSSE inserts on SOAP header?

    Like

  3. Looks like the JBoss implementation of the JAX-RS specification adopted the RESTEasy moniker. If you really have seamless integration you do not have to specify what it seamlessly integrates with. JAX-RS binds URIs to classes and methods with plug-in providers to handle mime types. Once in the JVM world of classes, parameters and methods, you automatically have “seamless” integration with ANY Java API.

    Like

  4. Looks like the JBoss implementation of the JAX-RS specification adopted the RESTEasy moniker. If you really have seamless integration you do not have to specify what it seamlessly integrates with. JAX-RS binds URIs to classes and methods with plug-in providers to handle mime types. Once in the JVM world of classes, parameters and methods, you automatically have “seamless” integration with ANY Java API.

    Like

  5. Where can I get my hands on your code? :-). I’ve built my own REST-ful web service framework based on Stripes (www.stripesframework.org), but that was a workaround.. your stuff looks much cooler, except I’m not seeing any validation, which I think I can work around if the framework is flexible enough.

    Are there callbacks during different lifecycle stages like pre- and post- binding, etc.?

    I’d be more than happy to help out with the project, too, as I’ve worked heavily with frameworks of this ilk..

    Like

  6. Where can I get my hands on your code? :-). I’ve built my own REST-ful web service framework based on Stripes (www.stripesframework.org), but that was a workaround.. your stuff looks much cooler, except I’m not seeing any validation, which I think I can work around if the framework is flexible enough.

    Are there callbacks during different lifecycle stages like pre- and post- binding, etc.?

    I’d be more than happy to help out with the project, too, as I’ve worked heavily with frameworks of this ilk..

    Like

Comments are closed.