Archive for May, 2012

Fork Jersey 2.x on GitHub

May 24th, 2012

While working full speed on Jersey 2.0, we are trying to be as transparent as possible. The JAX-RS itself is run in a transparent way – everybody can see the EG discussions by subscribing to users@jax-rs-spec.java.net or browsing the mailing list archives at http://jax-rs-spec.java.net. With Jersey 2.0 we are trying to track everything in the public Jersey JIRA – just click on the Agile tab and switch to the current milestone to see the planned tasks and the progress we are making.

One thing we haven’t been able to open up (due to firewall restrictions) is our internal code review process. We are using Gerrit to review every commit that goes into the public repository. We have hooks set up for the internally hosted Hudson to kick in for each review request and automatically verify that the proposed commit does not break the build if approved. All works great, but unfortunately isn’t available for external checkins (all checkins have to go through the internal Gerrit Git repository and only Gerrit pushes the changes to java.net once they are approved).

So, to make things more transparent and easier (and inviting) for potential external contributors, and people who want to keep an eye on what’s going on, I’ve been playing lately with making the Jersey 2.x sources available on GitHub as well. We’ve managed to set up a 3-way synchronization between GitHub, Gerrit and java.net which turns the GitHub Jersey 2.x workspace mirror into the first class citizen. The recently announced BuildHive free service from CloudBees helped to supply the pull request verification, so we are now able to handle GitHub pull requests in a similar way to our internal Gerrit review requests. While we will most likely still continue using our internal set-up to do the internal code reviews (due to better performance and integration with internal tools), we are now able to handle external pull requests in a nice manner. So you are now free to follow and/or fork Jersey on GitHub and eventually submit patches as pull request. Here is the link: http://github.com/jersey/jersey

Just remember, for us to be able to accept your contributions, you need to send in a signed OCA.

Proxy Client on Top of JAX-RS 2.0 Client API

May 4th, 2012

UPDATE (7/3/2012): Proxy-client module is now part of the regular workspace (instead of incubator) and get’s pushed to maven along with other Jersey modules, so no need to build it manually anymore.

Several JAX-RS 1.x implementations are providing proxy client API as one of the ways to access web services. The basic idea is you can attach the standard JAX-RS annotations to an interface, and then implement that interface by a resource class on the server side while reusing the same interface on the client side by dynamically generating an implementation of that using java.lang.reflect.Proxy calling the right low-level client API methods.

Jersey 1.x client API (and now JAX-RS 2.0 client API) leverages the fact REST (and HTTP) defines the standard set of operations, so unlike for JAX-WS type of web services, which are verb-centric, for RESTful web services the interface is uniform and thus there is no need for generating client proxies. The standard client API is static (has fixed set of operations – get, put, post, delete, …). Proxy client API may be seen as evil, as it creates tighter coupling between services and clients. However, some people do find it useful and it provides better opportunities for reusing JAX-RS concepts between services and clients, including name-bound interceptors, for example.

Few weeks back I quickly “hacked” a proxy client factory for Jersey as part of Jersey 2.0 and made some small incremental improvements since then. It is based purely on the current draft of the standard JAX-RS 2.0 client API, so should be usable with any JAX-RS 2.0 implementation, not just Jersey. Currently it lives in the “incubator” subfolder of Jersey 2.0 workspace, so if you want to give it a try, you have to check it out and build it yourself. The project includes a test that illustrates the usage, and also a simple example.

Building the Proxy-Client Project

To build it, first clone the Jersey repository, build Jersey, then switch to the proxy-client folder and build the proxy-client project. The following shell commands do that (assuming you have git and mvn installed):

git clone ssh://[your-java.net-user-id]@git.java.net/jersey~code jersey
cd jersey
mvn install
cd incubator/proxy-client
mvn install

Using/Playing with the Proxy-Client

The project has just one class – WebResourceFactory. Here is how it can be used:

Let’s say you want to access a web resource available at a URI that could be represented by the following URI template:

http://acme.com/rest/books/{book-id}

Let’s assume this resource can produce and consume application/json and application/xml and supports GET, PUT and DELETE operations. There is also a parent resource – http://acme.com/rest/books/ which accepts GET (returns a list of books) and POST (creates a new book). Here is one example of how you can model it using the interfaces with JAX-RS annotations and then access these resources using those interfaces and WebResourceFactory class:

Interface representing the “books” resource:

@Path("books")
public interface BooksResource {
    @GET
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    List<Book> getBooks();

    @POST
    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    Response createBook(Book book);

    @Path("{bookid}")
    BookResource getBookResource(@PathParam("bookid") String bookId);
}

Interface representing “books/{bookid}” subresource:

public interface BookResource {
    @GET
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    Book get();

    @PUT
    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    Book update(Book book);

    @DELETE
    void delete();
}

Accessing it from your application:

// create a new JAX-RS 2.0 target pointing to the root of the web api
Target t = ClientFactory.newClient().target("http://acme.com/rest/");

// create a new client proxy for the BooksResource
BooksResource booksRsc = WebResourceFactory(BooksResource.class, t);

// get list of books
List<Book> books = booksRsc.getBooks();

// get book resource by ID
BookResource bookRsc = booksRsc.getBookResource(bookId);
// get book object
Book myBook = bookRsc.get();
// delete book
bookRsc.delete();

I hope you got the idea. As you can see, the proxy factory can handle path parameters and can automatically create proxies for sub-resources. It can also handle other kinds of parameters such as header parameters, query parameters, form parameters and cookie parameters.

Give it a try and let us know what you think.