Tuesday, July 10, 2012

JAX-RS server: beyond hello world

Warning: This article is for the legacy JAX-RS 1.x API. Consider using the more up to date JAX-RS 2.x instead. This is not a recommended article to set that up. Take a look at the more recent article Maven JavaEE7 app in Netbeans 8 that demonstrates getting a JAX-RS 2.x based service going.


In my previous article on JAX-RS I dealt with creating a client that consumes a RESTful webservice. In this article I'm going to turn it around and use JAX-RS to expose a webservice. In a way that I myself can easily consume it from a Ruby on Rails client (proper test: make it cross technology boundaries). This service is going to expose some data as JSON, although you could take the next step and expose both JSON and XML.

In the client article I posed a generic interface which allowed a client to search for projects by name. The service would have to produce the data in this format:
[{  
      "active":true,  
      "id":1,  
      "name":"Razorblade supershave mark 2",  
      "company":{  
                 "id":1,  
                 "name":"Razorblade Ent.",  
                 "employees":[{"id":1,"name":"harry"},{"id":2,"name":"sally"}]  
                }  
     },  
     {  
       "active":true,  
       "id":9,  
       "name":"fortune cookie dispenser",  
       "company":{  
                  "id":2,  
                  "name":"Unfortunate Inc.",  
                  "employees":[{"id":5,"name":"gordon f."},{"id":7,"name":"sam stone"}]  
                 }  
     },  
     { "active":true,  
       "id":15,  
       "name":"fortune cookie baking device",  
       "company":{  
                  "id":2,  
                  "name":"Unfortunate Inc.",  
                  "employees":[{"id":5,"name":"gordon f."},{"id":7,"name":"sam stone"}]  
                 }  
     }]  

In this article I'll create a service that produces this. Since its a webservice we'll have no choice but to expose it through a webserver; I'll assume you are going to be deploying this on Tomcat 7 but if you are using a JEE6 capable application server (which has JAX-RS built in) I also provide the slightly alternative setup steps. Also as I explain in the client article there are many JAX-RS implementations, for this article too I'll be using the reference implementation called Jersey for Tomcat; if you use a JEE container it will already provide its own implementation (example: JBoss 7+ comes with RestEasy). If you have no experience with Java web development or deploying an application to something like Tomcat this article is a little out of your league at this point I'm afraid. My JSF 2 and JPA 2 on Tomcat 7 article goes into great detail and might provide you the prerequisite knowledge to be able to do what his article will assume you know how to do. At the very minimum read up about the HTTP protocol as that is basically what makes and drives RESTful webservices.

Remarkably exposing a service is less involved than consuming one; in this article I'll be dealing with:
  • Maven setup / dependencies (separate steps for Tomcat and JEE containers such as JBoss)
  • how to configure Jersey/JAX-RS
  • how to expose a service to GET data
  • how to expose a service to submit (POST) data


As it turns out there are quite a few variations on how to actually expose a service; I'm picking one that to me is the more logical, natural and above all readable way to do it that should cover most needs. In the future I'll add steps to the article to setup some proper security through Tomcat 7.

Tomcat 7 setup

This article will show two ways to setup: for Tomcat and for a JEE server; the latter is far less work. I'll also add JBoss 7.1 specific information, me being a JBoss enthusiast.

Maven
To expose a Jersey based JAX-RS service we need the following Maven dependencies which are all in Maven central. Note that if you have followed the client article also, there is going to be some duplication here. Note also that this is a slightly older article so it targets Jersey 1.x, not the newer Jersey 2.x.
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-server</artifactId>
    <version>1.18.1</version>
  </dependency>
  <dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>jsr311-api</artifactId>
    <version>1.1.1</version>
  </dependency>
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-servlet</artifactId>
    <version>1.18.1</version>
  </dependency>  
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>1.18.1</version>
  </dependency>

That jersey-servlet dependency seems to be a bit of a secret! Apparently it used to be part of the jersey-server dependency, but has been separated at one point in time.

If you deploy to a JEE6+ compliant application server you would mark the above dependencies as provided, since the application server itself does in fact provide a JAX-RS implementation. You will want to check which one because you will want to make the maven dependencies match up.

If you're not using Maven, the following dependencies are actually going to end up in the webapp (most of them transitive dependencies):
  • jersey-core 1.18.1
  • asm 3.1
  • jersey-server 1.18.1
  • jersey-servlet 1.18.1
  • jersey-json 1.18.1
  • jettison 1.1
  • activation 1.1
  • stax-api 1.0.2
  • jaxb-api 2.2.2
  • jaxb-impl 2.2.3-1
  • jackson-core-asl 1.9.2
  • jackson-jaxrs 1.9.2
  • jackson-mapper 1.9.2
  • jackson-xc 1.9.2
So compared to the jersey-client article, the asm, jersey-server and jersey-servlet dependencies have been added.

Web
The client is install, fire, go and can even work on the commandline. The webservice part of it requires additional setup however and to my amazement there are multiple ways to actually do that. I present here the one I found to most understandable version. Jersey exposes its services as a (clever) servlet, which we need to plug in the web.xml as follows:
  <servlet>
    <servlet-name>Jersey</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>jaxrstest.server.service;org.codehaus.jackson.jaxrs</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
      <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    
  </servlet>
  
  <servlet-mapping>
    <servlet-name>Jersey</servlet-name>
    <url-pattern>/REST/*</url-pattern>
  </servlet-mapping>  

Note the servlet-class; without the jersey-servlet dependency that class would be missing. This piece of configuration data contains two application specific elements you will want to know about.

First of all there is the config.property.packages init-param. This property tells the Jersey servlet in which packages we'll be putting our restful resources (or RESTful root resources as the JEE 6 tutorial likes to call it). You can put more packages than the one by separating them with a semi-colon like this:
<param-value>jaxrstest.server.service;package.some.other</param-value>

Be sure to put a package (or packages) of your own choosing here. In the above example I've also added a package that is part of the Jackson JSON mapping library; by doing so Jersey will find the Jackson mapper classes and use them. The Jackson POJO mapping features are better (read: produces more compatible JSON layouts) than what you get from Jersey itself.

Secondly there is the url-pattern that the servlet is mapped too; you should pick a pattern that does not clash with the rest of the web application. The pattern you put here is going to be used by Jersey to build up the actual URL under which services are going to be exposed.

Also note the POJOMappingFeature init parameter - this basically tells Jersey that we'll be exposing data as JSON (and thus the jersey-json dependency is needed). If you leave this parameter out you'll find that things still work... but generally not as expected.

JEE setup


Maven
Since JEE6 and up already provides JAX-RS out of the box, we don't need much; only the API to compile against.
  <dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>jsr311-api</artifactId>
    <version>1.1.1</version>
    <scope>provided</scope>
  </dependency>

Web
No configuration is needed. We only need to add a class to our application which indicates we want to expose a JAX-RS service, and where:
@ApplicationPath("/REST")
public class JaxrsApplication extends Application {
}

This is enough for a compliant JEE6/JEE7 container to make the magic happen. JAX-RS services will be exposed under the url WEB_URL/REST, so for example http://localhost:8080/jaxrstest/REST. Put whatever application path you like.

JBoss 7.x setup

If like me you're not rich, you use the community version of JBoss and you'll be stuck with outdated libraries. Luckily you can easily upgrade the built-in RestEasy module - and you should do that because the default version has some issues, such as not being able to use adapters. To upgrade RestEasy, go to the download page to get the latest version. Then:
  • unpack the file resteasy-jboss-modules-VERSION.Final.zip from it
  • unpack that resteasy-jboss-modules-VERSION.Final.zip file into your JBoss 7.1 modules subdirectory
  • If you do it correctly, you'll be asked to overwrite files: yes to all
Done! Note: If you are using JBoss 7.2 / EAP 6.1, you need to copy the unpacked files to the modules/system/layers/base subdirectory. See my JBoss 7 getting started article to learn how to build JBoss 7.2 yourself.

Creating a model

Since I'm aiming to produce exactly the same JSON data that the client article is set to consume, I'll re-use the model classes verbatim. Again, getters and setters left out to save space.
@XmlRootElement
public class Project {

  private boolean active;
  private long id;
  private String name;

  private Company company;

  public Project(){
  }
  
  public Project(long id, String name, boolean active, long companyId, String companyName, Employee[] emps){
    this.id = id;
    this.name = name;
    this.active = active;
    this.company = new Company(companyId, companyName, emps);
  }

  // getters and setters here
}


@XmlRootElement
public class Company {
  private long id;
  private String name;
  private Employee[] employees;

  public Company(){
  }

  public Company(long id, String name, Employee[] emps){
    this.id = id;
    this.name = name;
    this.employees = emps;
  }

  // getters and setters here
}

@XmlRootElement
public Employee {
  private long id;
  private String name;

  public Employee(){
  }

  public Employee(long id, String name){
    this.id = id;
    this.name = name;
  }
  // getters and setters here
}

Only a few things to note:
  • the XmlRootElement annotation; that is a JAXB annotation that basically marks the pojo class as a complex type to be used in mapping the data; either JSON or XML.
  • the properties of the beans match the labels as you'll find them in the JSON data
  • array of employees in the JSON data, array of employees in the Java class. You can however replace the array type with a List<Employee> type if you so please, it magically works.
Convention over configuration: you're best off just using the exact same property field names as you find them in the JSON data, or else you'll have no choice but to add extra annotations to provide mapping names.

Creating a service class

Now that we have our model, its time to create a class which is going to serve as the "project" service; the service through which we are going to expose the RESTful functions that operate on our projects; the project search to be more precise. But we'll likely want to define more functions that operate on projects so from the many different ways the API can be used to expose a service, here is again the one I find the most logical. Put this class in the package you configured in that servlet init param (in my case the jaxrstest.server.service package)!
@Path("/project")
public class ProjectResource {
  // things and stuff here
}

Lets take it one step at a time. This minor piece of code maps our service to the /project path. At this point the question arises: but what is going to be the full HTTP URL? Well assuming that:
  • We're running the webserver on the localhost on port 8080
  • Our application's web context is 'jaxrstest'
The full URL of our project service is going to be:

http://localhost:8080/jaxrstest/REST/project/

If we define that in tokens:

HOST/CONTEXT/JERSEY-URL-PATTERN/PATH

But we're not there yet - we have yet to expose our project search function. What I want to do is match the pattern as I documented it in the client article, which was along the lines of:

/REST/project/search/:NAME

Where :NAME is to be replaced with a (partial) project name to search for. Given that requirement we can lay down the service declaration as follows:
  @GET @Path("/search/{name}")
  @Produces("application/json")  
  public Project[] search(@PathParam("name") String name) {
   ...
  }

Whoa, Four annotations for one service call. Of course I picked a rather involved example, so let's examine it.

First of all the @GET annotation should not leave anything up to the imagination; we expose this service as a GET request, which should be used to fetch information. The @Path annotation binds our search function to a very specific path under /project: namely /search followed by something that should be mapped to a variable parameter; the {name} part is what tells JAX-RS that it is in fact variable. The @PathParam annotation is then used to in fact bind the variable in the URL to the parameter of the method.

And then there is the @Produces annotation which again does not leave anything up to the imagination; it defines the content-type that the method will be producing. In this case we'll be exposing the data as JSON.

Lets define an actual body for the service call. Generally at this point you would of course fire off a query to a database and actually return a filtered list of results through for example JPA; in our case lets keep it simple and just create some objects:
    Project[] ret = new Project[3];
    Employee[] emps1 = {new Employee(1, "Donald"), new Employee(2,"Hewey")};
    Employee[] emps2 = {new Employee(3, "Scrooge"), new Employee(4,"321-123")};

    ret[0] = new Project(1, name + " 1", true, 1, "Super duper company", emps1);
    ret[1] = new Project(2, name + " 2", true, 1, "Super duper company", emps1);
    ret[2] = new Project(3, name + " 3", true, 2, "Super duper company 2", emps2);
    
    return ret;
This will just echo back whatever search query you pass in the project names. A useful way to mock some test data and still see that it does "something".

At this point you're ready to deploy your webapp, fire up Tomcat and invoke the URL: http://localhost:8080/jaxrstest/REST/project/search/test. During startup you can already spy some interesting logs that indicate that things are going well for us.
9-jul-2012 17:05:13 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
  jaxrstest.server.service
9-jul-2012 17:05:13 com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
  class jaxrstest.server.service.ProjectResource

Be sure to alter that URL to your personal environment using the description I gave you earlier. If everything is correct, you'll be greeted with the JSON data as posted at the top of this article, only as one long line. If not: did you by any chance forget to set that POJOMappingFeature init parameter?

JResponse - our list friend

To receive an array and use it is easy; to produce an array (in a statically typed language like Java) is cumbersome. It would be nicer if we could just return a generic list of projects in stead of an array. This is one of those things that has vastly improved during the time it took for JAX-RS to mature into the API it is today. To make our life incredibly easy we can use the JResponse class (as apposed to the old Response class) which preserves the generic type information for us.

Translating the code is as simple as this:
  @GET @Path("/search/{name}")
  @Produces("application/json")  
  public JResponse<List<Project>> search(@PathParam("name") String name) {
    
    // normally this would do a database search
    List<Project> ret = new ArrayList<Project>();

    Employee[] emps1 = {new Employee(1, "Donald"), new Employee(2,"Hewey")};
    Employee[] emps2 = {new Employee(3, "Scrooge"), new Employee(4,"321-123")};

    ret.add(new Project(1, name + " 1", true, 1, "Super duper company", emps1));
    ret.add(new Project(2, name + " 2", true, 1, "Super duper company", emps1));
    ret.add(new Project(3, name + " 3", true, 2, "Super duper company 2", emps2));
    
    return JResponse.ok(ret).build();
  }

This should produce exactly the same JSON output as the array example. A general use case would be: fetch list of Project instances from the database using JPA, expose it through JAX-RS service. Easy and only a few lines of code involved.

What about a client?

The client article should be able to help you there, but I'm a firm believer of crossing technology boundaries to really put something to the test. If you're familiar with Ruby on Rails, I created this very simplistic (rails 3) client class using the HTTparty gem (don't forget to add it to your gems file) to be able to consume the project search service.
require 'rubygems'
require 'httparty'

class ProjectResource
  include HTTParty
  base_uri 'http://localhost:8080/jaxrstest/REST/project'
  format :plain
  headers 'Accept' => 'application/json'

  
  def self.search_projects(name)
    
    #this performs a GET request to the project search, returning the JSON data as plain text. That way we can easily use ActiveSupport to deserialize the data into model class objects.
    data = get("/search/#{name}")
    projects = ActiveSupport::JSON.decode(data)
    return projects
  end  
end
Where 'projects' is then an array of Project objects, which are simple Rails model classes that match the Java ones above. The fact that they're ActiveRecord model classes is what makes it possible for ActiveSupport to magically translate the JSON data into the appropriate model types without needing any hint at all. As an example, here is a stripped version of the Project model class:
class Project < ActiveRecord::Base
  
  attr_accessible :id, :name, :company, :company_id, :active 
  belongs_to  :company

  ...
end
How to actually setup a Rails application and use the above code is way beyond this article, but I'd just want to give an idea of how such a thing translates to another language/platform. Of course Rails being Rails there are likely dozens of alternatives to be able to consume a web service; I picked this route because it is basic and lightweight.

You don't have to write any client to test this out, you could also install the excellent HttpRequester Firefox plugin, which allows you to fire very specific HTTP requests to an url. That way you can fire a GET request with the accept header set to application/json. If you're not a Firefox user I'm sure there is a similar plugin for your browser of choice, or you could create a simple java command line thing using the Apache HttpClient API.

Producing multiple content-types

So far we've locked our service down to JSON, but what if some clients must remain in the stone age and demand XML? Easy enough, if you look in the Jersey reference manual you'll quickly spot that the content-type for XML is "application/xml". But what if we wanted to support both json AND xml output? It would really stink if we had to duplicate each service call. Luckily you don't have to, we can augment our service call as follows:
  @GET @Path("/search/{name}")
  @Produces({"application/json", "application/xml"})  
  public Project[] search(@PathParam("name") String name) {

This one method can now service both JSON and XML data. But which one is going to be the default? Jersey at least, it seems, favors XML. If you navigate to the service call in a browser you'll now get XML output as a result. Our Ruby client as defined above however, provides an accept HTTP header of 'application/json'. That accept header makes it so a call to the same URL will in fact produce JSON data as a result!

Reversing the flow: pushing data

Until now the article has been dealing with one way to provide data to a client. Now lets examine the other way around: how does a client push data to our service? Since this is fully HTTP based, the answer lies in the request method. Until now we've been dealing with GET requests, but there is also HTTP POST, PUT and DELETE. Delete won't need any explanation, but POST and PUT are subject to a certain convention you'll find common in RESTful services - POST is used to add something, PUT is used to update something.

If you've ever built any kind of web application you've likely built a web form which is submitted to the server through a POST request; that same web form can likely be used to either add or update a record. Now there is nothing stopping you from creating a RESTful service which reacts to a POST request and both inserts and updates data; there is nothing stopping you from using PUT in stead. But when it comes to providing a service, you want to lay down a very precise and clearly defined interface or contract - it is not a bad idea at all to actually separate insertion and modification into two separate methods and following the convention for one very simple reason: the ability to make safe assumptions which is the biggest step towards self-documenting code.

Okay, lets create a method to add a company to our system. Since I've been pushing JSON until now, let's in fact make our client offer the data in JSON format.
  @POST @Path("/company/add")
  public void createCompany(Company comp) {
    // normally you'd do something like use JPA to persist the company to the database.
    System.out.println("CREATING COMPANY WITH NAME: " + comp.getName());
  }

This method is actually more flexible than you'd think as the client can transmit the data both in JSON and XML format and both will work; if you'd want to lock the service down to a specific type then you could add a @Consumes annotation to the code.

Now this will certainly work, but for our client it lacks critical feedback. The company is now stored, but how does one uniquely identify this company to for example be able to fetch it later or bind an employee to it? Much like a GET method, we can return something from our POST method. You could echo back the entire Company object but for example with an ID property added, but a more clever solution is to return some sort of result object which can also communicate success or failure.
@XmlRootElement
public class IdResult {

  private long id;
  private boolean ok;
  private String msg;
  
  public IdResult(){
  }
  
  public IdResult(long id){
    this.id = id;
    this.ok = true;
  }
  
  public IdResult(String msg){
    this.ok = false;
    this.id = -1;
    this.msg = msg;
  }

  // getters and setters here
}

With that simple object we can now give proper feedback to the client:
  @POST @Path("/company/add")
  @Produces("application/json")
  public IdResult createCompany(Company comp) {
    // normally you'd do something like use JPA to persist the company to the database. We need an ID to return, so just generate something.
    System.out.println("CREATING COMPANY WITH NAME: " + comp.getName());
    return new IdResult(System.currentTimeMillis());
  }

Time to try that out. With the path set the full url would be http://localhost:8080/jaxrstest/REST/project/company/add; if you put that in a browser you should get a "method not allowed" error message (since we're sending a GET request to something which expects a POST request). To do a proper test you could create a simple client method or by using that HttpRequester firefox plugin I mentioned earlier. Use the following POST request body, which is our company in JSON format sans employees:
{"id":0,"name":"My super duper company"}

To be able to actually send this POST request you have to make sure that you are setting the content-type of the request to application/json! As an accept header you have to set application/json as well since that is what the service call @Produces. the output of such a request would now be like this:
{"id":"1341924925250","ok":"true"}

Lets add another Ruby on Rails example here just to keep the article consequent. Since we have to set an explicit content-type, its best to put update code in a separate resource class specifically aimed at doing update actions. To get the result you could define another IdResult model class and deserialize the JSON response like in the previous client example, but to be original lets skip that and simply let HTTparty do some work for us. It can actually deal with JSON response data and return the individual fields as a hash.
class ProjectUpdateResource
  include HTTParty
  base_uri 'http://localhost:8080/jaxrstest/REST/project'
  format :json
  headers 'Accept' => 'application/json'
  headers 'Content-Type' => 'application/json'

  def self.add_company(name)
    
    #construct a company model object and serialize that to JSON (limiting to specific fields)
    company = Company.new(:id => 0, :name => name)
    data = company.to_json(:only => [:id, :name])

    #post the JSON data as the body of the request and get the response
    res = post("/company/add", :body => data)
    
    #get the individual fields from the response
    ok = res['ok'] == 'true'
    id = res['id']
    msg = res['msg']
    
    #should do some error checking here and throw an exception where necessary.
    puts "----------------------------- OK: #{ok}, ID: #{id}, MSG: #{msg}"
    return id
  end
end
Again a very basic and lightweight way to do it and there are probably many alternatives to do it in a more RESTful way. It doesn't matter, what matters is that we get the data to our service in a way that is expected and we can read out the response in an easy way. At this point you may run into many HTTP errors, all of them caused by the content-type and the accept headers of the client not matching with what the services produces and consumes. Its a question of fiddling until something works.

Working with dates in your models

Dates are a difficult thing, because they come in so many shapes, sizes and orders. Therefore marshalling/unmarshalling a Date is not something that can just happen; likely you will want to impose a little control over this. The easiest way of all is to just use dates in textual format, but if someone sends you an invalid date you can't let the API deal with that, you have to parse and validate yourself. My choice to attack this problem is to use a JAXB adapter.

Watch out though!: older versions of Jackson (the JSON mapping library often used in JAX-RS implementations) did not handle the adapters at all. Make sure you are using an up to date version of Jackson / your JAX-RS implementation. If you're a JBoss 7.1 user, check the start of this article for upgrade steps.

First of all we need our adapter, which is as simple as this:
public class DateAdapter extends XmlAdapter<String, Date> {

    @Override
    public Date unmarshal(String v) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        return sdf.parse(v);
    }

    @Override
    public String marshal(Date v) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        return sdf.format(v);
    }
}

This class will work with dates in Dutch format, adapt the pattern to what you need. Now we need to tell our JAX-RS implementation that we want to use this adapter to marshall/unmarshall dates. Lets take a more extreme example and you are using JPA entities as your model classes (just to show that you can), it could turn into something like this:
@Entity // JPA
@Table(name="person") // JPA
@XmlRootElement // JAX-RS
public class Person {

  @Id // JPA
  @GeneratedValue // JPA
  private int id;

  private String name;

  @Temporal(TemporalType.DATE) // JPA
  @XmlJavaTypeAdapter(DateAdapter.class) // JAX-RS
  private Date birthdate;

  // getters and setters
}
Its a bit annoying; I have not found a way to set an adapter globally yet but I'm sure there is a way to achieve this result in some way...

Dealing with CORS

CORS, or "Cross Origin Resource Sharing" is a protection mechanism built into modern browsers that basically prohibits websites from making ajax requests to just any other server; by default javascript is only allowed to make requests to the host (and port) from which the resource was serviced. That's a bit limited especially when you want to make ajax requests to a RESTful service which will almost never be the host which services the web application.

To be able to get around that you need to setup CORS on your server and it is surprisingly simple on Tomcat. Simply make sure that your Tomcat version is up to date (IE. if you run Tomcat 7, make sure you are running the latest one) and then simply configure this filter in your web.xml:
  
    CorsFilter
    org.apache.catalina.filters.CorsFilter
  
  
    CorsFilter
    /REST/*
  
Be sure to match the URL pattern to whatever you URL pattern you have mapped your RESTful service too. If you are not using Tomcat, you'll have to dig into your server's manual to figure out how to properly setup CORS, or possibly manually add the headers to the response with your own filter. For further reading when using Tomcat: the documentation page.

Is it really a good idea to mix JPA and JAX-RS?

Int this article I've shown a few examples where JPA entities are exposed in the webservice calls. That is certainly very useful as it prevents duplicate code, but is it really a good idea?

The answer is unfortunately: absolutely no. There are a myriad of problems attached to exposing the database layer directly in the webservice interface, as that is what you're doing. Lets list a few:
  • Any field you add, change or remove in an entity directly affects and changes the webservice contract!
  • You need to actively exclude properties from being serialized; all are exposed to the outside world by default.
  • JAX-RS serializes entities, so all their lazy properties will be hit

What it boils down to is that you have absolutely no freedom and you severely lock down your capabilities to make any changes to the data model of the application. Basically if an entity is exposed to the outside world, it better stay exactly the way it is. If you change it, any client depending on its old state will likely break unless it is modified to match the new serialized state.

You do not want that head ache. You should use POJO value objects which expose the minimum amount of information. If you then change an entity you don't necessarily have to change the VOs that match it - you only change how the data in the VOs is fetched from the entity. Separation of concerns - it won't lead to less code, but it will prevent burn out.

Securing our web service

One day I'll provide exact steps on how to configure Tomcat 7 to do such things as utilizing HTTPS and how to setup HTTP digest authentication. But that will require further experimentation on my part as well.

Time to call it a day

Not an entire manual on setting up JAX-RS services but not hello world either. I hope with this article I've given you the leg up that makes you productive with JAX-RS as quickly as possible. For further reading I suggest you get a good book on the API, but you may also want to check out the JEE 6 tutorial chapter on JAX-RS. For Jersey specific documentation there is the Jersey reference manual. And I'd like to repeat once more that if you were looking for documentation on creating a client using JAX-RS, I have a whole article dedicated to that topic.

Good luck with your project!

Monday, July 9, 2012

JAX-RS client: beyond hello world

So, RESTful webservices. You came here, so you must be interested in invoking a RESTful webservice from a Java client. At this point you must have also figured out that JAX-RS is in fact the way to go when it comes to invoking RESTful webservices, even though technically you could do it with a simple URLConnection or a little more robust: the Apache HttpClient API. Of course JAX-RS offers some benefits, the biggest one being that it takes a big pile of work away from you.

Before you can use JAX-RS, you must first understand JAX-RS. The primary thing to understand is that it is only a specification: it doesn't actually do anything. You can't download JAX-RS and expect to be making connections to servers. To actually be able to do anything you need something that implements the JAX-RS specification and in true Java fashion, you have a plethora of choices. Third party offerings include CXF, Restlet and RESTEasy - Oracle delivers a reference implementation called Jersey; that's what I'll be using for the purpose of this article but since its a specification, it doesn't really matter which implementation you're using; the difference will mostly be in the setup part. If you deploy the client as part of a JEE 6+ application, a JAX-RS implementation is already provided by the container.

Also be aware that Jersey is already an API with a development history; it has grown up a lot since its 1.0 days with plenty of added features and improvements in the way things are done; some of which are not exactly documented clearly yet. Plenty of articles and blogs on the net will refer to how things were done in the earlier days; do keep an eye out for the date of a posted article to know how accurate the information in it is going to be. For this article I made an effort to figure out what is the more up to date way to use the API (at the time of writing of course), but perhaps I missed something.

The Jersey website actually hosts a somewhat useful reference manual; I say somewhat because like most reference manuals its a document without focus and therefore hard to follow in that "I'm new, how do I begin" state that we all begin in. So it didn't stop me from having to hunt through many a forum to get to the point where I could actually effectively put JAX-RS to work for me. Most articles I found on the net of course went no further than the bare basics; how do you setup a hello world service, how do you create a hello world client. Well not me, I'm diving a bit deeper here. To not make the article too complex I'm only focusing on creating a RESTful client here. The server/service part of it I have put in a dedicated article (because again: had to hunt through forums, make guesses and do plenty of experiments to get it to work the way I wanted).

What this article will cover is the following:
  • Maven setup / dependencies
  • how to connect to a server
  • how to invoke a service and get the results - with nested objects
  • how to deal with collections and arrays
  • how to post data to a service
  • performance enhancement
  • dealing with authentication

Then there is the question of protocol: what data format to use? The most common ones are XML, YAML and JSON - I'll be going for the one that makes the most sense to me, which is JSON.

Before we begin I'd like to stress one thing: I'm not a JAX-RS expert. This article is in no way in its final form and will continue to grow much like most of my articles expand and improve over time as I continue to learn from my own mistakes. Feel free to point out glaring mistakes or omissions in the comments; I actively maintain my articles so you can be quite sure that mistakes will be fixed.

Setting up Maven

To get going with Jersey you need only a few dependencies which are thankfully in Maven central. To keep it basic lets assume you want to deploy to Tomcat and not a full JEE application server. You would declare your dependencies as follows:

    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-json</artifactId>
      <version>1.18.1</version>
    </dependency> 

To know the latest version of Jersey, simply consult Maven central search or here: Jersey in Maven central

If you are deploying to for example Glassfish 3 or JBoss 7 you would mark these dependencies as provided, since all required dependencies are already there in the container. You will probably want to figure out which JAX-RS implementation is delivered with your application server so you can make your compile time dependencies match up.

That's it for the client (to also provide a RESTful service, you would include the jersey-server artifact). Of course Maven being Maven, this will provide you with a whole host of transitive dependencies. For the people who don't use Maven (please, come to the dark side) the following list of dependencies are actually going into the webapp with the Jersey 1.18 version:
  • jersey-core 1.18.1
  • jersey-client 1.18.1
  • jersey-json 1.18.1
  • jettison 1.1
  • activation 1.1
  • stax-api 1.0.2
  • jaxb-api 2.2.2
  • jaxb-impl 2.2.3-1
  • jackson-core-asl 1.9.2
  • jackson-jaxrs 1.9.2
  • jackson-mapper 1.9.2
  • jackson-xc 1.9.2
Note that both JAXB and Jackson are in this list. Both of these APIs are used by Jersey to do mapping of data to objects; JAXB for XML and Jackson for JSON. For ease of deployment JAXB annotations can be used on your pojos to provide the mapping information no matter which data format is used; Jersey will still use Jackson under the hood to do the actual mapping work.

What about a server?

To be able to build a client you need a server that can be invoked, at least to test stuff out. Unfortunately that is a bit of a challenge posed to me in this here article. But in order to understand how the client works you don't really need a server; you only need what the server outputs which in our case is a blob of JSON formatted data. So without further ado lets define that exact blob.

Somewhere in the world we have a service that allows us to search for projects. A project has basic properties such as a name and a deadline, but it is also tied to a company. A company on its own has a name and an address and a list of employees. Sounds pretty basic, but in that one example we cover nested objects and a collection.

In JSON terms, that would translate to the following which I'll pretty print for the purpose of making it possible to see what's going on (in a normal circumstance you don't want unnecessary whitespace in your datastream):

[{
  "active":true,
  "id":1,
  "name":"Razorblade supershave mark 2",
  "company":{
             "id":1,
             "name":"Razorblade Ent.",
             "employees":[{"id":1,"name":"harry"},{"id":2,"name":"sally"}]
            }
 },
 {
   "active":true,
   "id":9,
   "name":"fortune cookie dispenser",
   "company":{
              "id":2,
              "name":"Unfortunate Inc.",
              "employees":[{"id":5,"name":"gordon f."},{"id":7,"name":"sam stone"}]
             }
 },
 { "active":true,
   "id":15,
   "name":"fortune cookie baking device",
   "company":{
              "id":2,
              "name":"Unfortunate Inc.",
              "employees":[{"id":5,"name":"gordon f."},{"id":7,"name":"sam stone"}]
             }
 }]

Consider this a full dump of the database; there are only three projects in here. This is not typed by hand by the way - this is the output of a Ruby On Rails service that I created for testing purposes. The fact that I could whip up my Java client and it "just worked" is what really made me go "WOW!", that hasn't happened a very long time. In my JAX-RS server article I'll be basically creating a simplified Java version of the service that produces the exact same output.

If you're not familiar with JSON I urge you to go read up on it a bit, but the above should still be human readable for a programmer. [] represents an array of elements, {} represents the start of a complex type which in Java terms will translate into a POJO bean. Quite easy to read, not as easy to type.

Defining the model

I mentioned POJO beans. To be able to read out the above JSON data we'll need a model to be able to store the information. Three complex types makes three Java POJO classes. I'll leave out the getters and setters to save some space.

@XmlRootElement
public class Project {

  private boolean active;
  private long id;
  private String name;

  private Company company;

  // getters and setters here
}


@XmlRootElement
public class Company {
  private long id;
  private String name;
  private Employee[] employees;

  // getters and setters
}

@XmlRootElement
public class Employee {
  private long id;
  private String name;

  // getters and setters
}

Only a few things to note:
  • the XmlRootElement annotation; that is a JAXB annotation that basically marks the pojo class as a complex type to be used in mapping the data; either JSON or XML.
  • the properties of the beans match the labels as you'll find them in the JSON data
  • array of employees in the JSON data, array of employees in the Java class. You can however replace the array type with a List<Employee> type if you so please, it magically works.
Convention over configuration: you're best off just using the exact same property field names as you find them in the JSON data, or else you'll have no choice but to add extra annotations to provide mapping names. With our model in place we can now go ahead and write our surprisingly simple client call.

Invoking the call

Now we get to the interesting part. The webservice we're talking with provides a service which allows us to search for projects by a (partial) name. The imaginary RESTful url to invoke is:

http://www.superpeople.com/REST/

Under that URL are all the different services, of which our project search which can be invoked as follows through a GET request:

http://www.superpeople.com/REST/project/search/:NAME

In that url :NAME is to be replaced with our partial project name. The services is structured such that all project related functions are under the /REST/project/ url. Lets define the simplest way to invoke this service and get the results without worrying too much about performance just yet. This is done in only three steps:

1) obtain a JAX-RS Client instance
2) create a WebResource using this Client to the URL you want to invoke
3) actually invoke it, optionally setting some parameters

Creating a Client is very little work and is pretty much boilerplate code. There are multiple ways to actually create a client, I picked this as the "way I'll always do it":

  public Client createClient(){
    
    ClientConfig clientConfig = new DefaultClientConfig();
    clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
    clientConfig.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);    
          
    Client client = Client.create(clientConfig);
    return client;
  }

The ClientConfig class allows for some basic properties to be set; most of which you will likely not ever have to deal with. The important one here is the FEATURE_POJO_MAPPING setting: this tells the JAX-RS client that we'll be dealing with JSON data.

Okay on to the actual web invocation.

 
public static final String HOST = "http://www.superpeople.com/REST/"; 
public static final String PROJECT_URL = HOST + "project/";
public static final String PROJECT_SEARCH = "search";

public Project[] searchProjects(String name){
  
  Client client = createClient();
  WebResource res = client.resource(PROJECT_URL);

  return res.path(PROJECT_SEARCH + "/" + name)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .get(Project[].class);
}

The first thing that may seem off to you are those constants which are hardcoded; later on we'll make that a little more robust and a little less hardcoded but for now lets keep it simple. Basically we split the resource up into two parts: the 'project' resource and the 'search' function. As you can see a WebResource is constructed for the project resource. Later on we'll see why this is good design, but for now take good notice of that path() method being called; there we pass in the actual function that we want to invoke plus any variable parameters that the service call may provide. In our example the search demands a partial project name to be passed, so that's what we dump into the path.

Let's say that we search for 'fortune'; the full URL invoked will then become:

http://www.superpeople.com/REST/project/search/fortune

The imaginary service will then do a search for projects with a name starting with the word 'fortune';which in the case of our massive three project database should return two results.

Moving along to the accept method, that shouldn't need much imaginative power. Here we declare that the service should expect JSON data.

Finally the method that does all the work: get. Upon this call the restful service is actually invoked and the results will be translated into that which we pass into get() as a parameter; in this case an array of Project objects. And that's where all you have seen so far comes together:

- our JSON data structure as delivered by the phantom web service
- the pojo classes with the minimal annotations that matches said JSON data structure
- the JSON support we activated through the ClientConfig settings

All that equals magic happening during the get() invocation (because this is a GET request; if it would be a POST request you would use the post() method). Jersey will at this point read the JSON data and under water use the Jackson API to translate that data into the object hierarchy we've built, including mapping to child objects and even our employee array in the Company object; it just works. And if it doesn't work then you'll get a very clear error stating where the typo is.

Of course even though magic is being performed, its still magic under your control. YOU have to define the proper pojo object structure with proper naming. YOU have to know the exact URL layout of the service to invoke. YOU have to know in what way data will be returned (single object, array of primitives, array of objects). The tool is not doing the work for you - it is making your work easier. Exactly how it should be.

Now we've built our client call to return an array of projects. But what if you wanted a list of projects in stead? Simply swapping out the array type with a List type doesn't cut it in this case, this is how you do that:

  return res.path(PROJECT_SEARCH + "/" + name)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .get(new GenericType<List<Project>>() {});


The GenericType object is there to help the translation to the proper generic List type in such a way that the compiler likes it. From now on, it's copy/paste logic.

URL parameters

Let's say the service definition is actually that you invoke the URL like this:

http://www.superpeople.com/REST/project/search?name=fortune

The only thing that changes is the way we do the invocation.

  return res.path(PROJECT_SEARCH)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .queryParam("name", "value")
            .get(Project[].class);

If you have multiple query parameters then simply call queryParam() multiple times. Alternatively you could use this too:

  MultivaluedMap<String, String> params = MultivaluedMapImpl();
  params.add("name", name);

  return res.path(PROJECT_SEARCH)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .queryParams(params)
            .get(Project[].class);

Which would allow you to set multiple parameters in one go, at the expense of more boring boilerplate code.

Time to put that to the test

You're now already at the point where you can try it out. Since you are interested in creating a JAX-RS client, you must have some sort of RESTful service that you want to be able to invoke. If you do not - well you can always try to create one for example by following my server article.

But of course where there is a will to be lazy, there is a way to be lazy. You don't need any service; the only thing you need is a way to do a GET request to some text file which will literally return the JSON data that I provided earlier. Paste that in a file test.json and make sure you get get to it through a web url even if it is on the localhost. Then use the following bit of code to use it:

  WebResource res = client.resource("http://localhost:8080/test.json");

  return res.accept(MediaType.APPLICATION_JSON_TYPE)
            .get(Project[].class);

It should work just fine even in the pretty printed format.

The reverse situation: sending data

Until now we've been leeching information from our phantom service. What if we'd actually want to return something? Like create a new company to which projects and employees can be bound?

That is in fact quite simple but it requires a little theory. Until now we've been dealing only with GET requests; in other words requests that fetch something. To do modifications we need to use the other HTTP request methods: POST, PUT and DELETE. RESTful webservices tend to define a convention: POST is used to add information, PUT is used to update information. I hope I don't have to explain what delete will be used for :)

So in order for our client to be able to send something we first need the contract; our phantom service requires us to POST JSON data to the service url /project/company/add and will in return give a JSON complex type as an answer in the form of this IdResult object:
@XmlRootElement
public class IdResult {

  private long id;
  private boolean ok;
  private String msg;
  
  public IdResult(){
  }
  
  // getters and setters here
}

Which in JSON terms may look something like this for a success result:
{"id":"1341924925250","ok":"true"}

With that knowledge and the IdResult object at hand, we can construct our client call.
public static final String COMPANY_ADD = "company/add";

public IdResult addCompany(String name){
  
  Client client = createClient();
  WebResource res = client.resource(PROJECT_URL);

  Company company = new Company();
  company.setName(name);

  return res.path(COMPANY_ADD)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .post(IdResult.class, company);
}

And really, that's all there is to it. JAX-RS takes care of translating our Company object to the JSON body of the POST request and will also translate the JSON response sent back by the service into the IdResult object through that one post() invocation. Powerful stuff huh?

Making it better: stop hardcoding stuff

In the code I gave you until now the actual host of the service was embedded in the code. That may work for development and testing purposes, but if you put a REST client in production you will want to be able to manage the actual host URL outside of the code; for example you may have a completely different host URL for test/acceptance and production environments, in which case it depends on where the application is deployed which URL is to be used.

How to actually configure the URL depends on what you have available. Some options:
  • Pass it as a system property to the java command (-Dresturl=...)
  • In case of JBoss: define it in the property service
  • Store it in a settings database table
There are probably more solutions to be found but I believe in the power of no more than three and lets be honest: the first impulse anyone is going to have is store it in a database. My JSF 2 and JPA 2 on Tomcat 7 article can help you to write the code to do exactly that.

Making it better: re-use objects

The code as it is now has you creating a Client and a WebResource each time you do a call. These are quite expensive operations and as it turns out: you need to create them only once. We're talking about a stateless design here, you can safely re-use both the Client and the WebResource class in multiple threads without risk of collision. So lets do exactly that. First of all, lets isolate the actual initialization. How to design the code is pretty much a personal thing. I like to have setup in one place, so I tend to create an abstract base class in which I deal with it. Something like this:
public abstract class RestBase {

  public static final String PROJECT_URL = "/project/";
  
  protected static Client client = null;
  protected static WebResource PROJECT_RESOURCE = null;
  
  public static void init() {
    
     ClientConfig clientConfig = new DefaultClientConfig();
     clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
     clientConfig.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);    
          
     client = Client.create(clientConfig);
     
     // whatever database logic you have to get the host name from the database
     String hostname = SettingsDao.getSetting("REST_host");

     PROJECT_RESOURCE = c.resource(hostname + PROJECT_URL);
     
     // initialize other resources here
  }
}

This is the base class for all RESTful client services I'll be creating (which just happens to copy/paste very nicely). It has a method to initialize the one Client object we'll be exposing On top of that it initializes all the RESTful resources in one go and exposes them to subclasses. What's with all the statics I hear you wonder!? I know, it's not object oriented design. But so what? This code at least is easy to use, as we'll see in a moment. Next up is the project client service:
public class RestProject extends RestBase {

  public static final String PROJECT_SEARCH   = "search";
  public static final String PROJECT_GET      = "get";

  public static List getProjects(String name) {

    return PROJECT_RESOURCE
            .path(PROJECT_SEARCH + "/" + name)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .get(new GenericType<List<Project>>() {});
  }

  public static Project getProject(long pid) {

    return PROJECT_RESOURCE
            .path(PROJECT_GET + "/" + pid)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .get(Project.class);
  }

Huuuuu, more statics. You may not like that, in which case I challenge you to change it to your liking. Me? I think 100% stateless design is only hindered by the need for object creation before you can actually invoke something.

Note how I added a second phantom call just to make a little more exciting. The JSON data that this call may return to match our client code will look like this:

{
  "active":true,
  "id":1,
  "name":"Razorblade supershave mark 2",
  "company":{
             "id":1,
             "name":"Razorblade Ent.",
             "employees":[{"id":1,"name":"harry"},{"id":2,"name":"sally"}]
            }
}

So only one "complex type" which maps to our Project pojo class. As you can see the code manages that by simply passing in Project.class to the get() method. You know, for once this is an API that is really cleverly designed.

Now you also see the benefit of splitting the project resource from the actual functions that are exposed through the project URL; the same 'project' web resource can then be re-used to call the different functions ('search' and 'get' in this case). That minimizes the amount of bootstrapping that needs to be done.

Speaking of bootstrapping: that init method still needs invoking. A context listener can help us do that. The listener will be invoked upon deployment of our web application.

@WebListener  
public class InitContextListener implements ServletContextListener {
  
  private static volatile boolean initialized = false;
  
  public void contextDestroyed(ServletContextEvent ev) {
    
  }

  public void contextInitialized(ServletContextEvent ev) {

    if(initialized == false){

      RestBase.init();
      initialized = true;
    }
  }
}

And there you have it. Now as I said most of this is subject to personal taste. You may in fact skip the RestBase class altogether and simply initialize a Client instance per client service class you create. You may move all the setup logic in RestBase directly into the InitContextListener. If performance is not much of an issue because you do only a handful of calls sporadically, you may just want to use the "simple" way of doing things that the article began with. Don't re-use anything, just initialize on the spot, use it and discard it.

Whatever you feel comfortable with, and I do urge you to think about it and experiment a bit with it to find that which is comfortable to you (and your colleagues).

You can also simply run as a command line application at this point, assuming you have your project dependencies properly setup (goes pretty much automatic when you have a Mavenized project).

public static void main(String[] args){
  
    RestBase.init();
    
    List<Project> projects = RestProject.getProjects("fortune");
    System.out.println("Got " + projects.size() + " projects!");  
}


Plugging in Apache HttpClient

By default Jersey will simply use the JDK features to do HTTP calls, which boils down to the usage of HttpURLConnection and HttpsURLConnection. For simple services this will be sufficient although people have been known to experience sporadic failures when using these classes in combination with certain (unstable?) web servers. No matter since these classes have been basically made obsolete by the incredibly powerful, feature complete, fast and easy to use HttpClient built by our friends at Apache. So is there a way we can make Jersey use it?

Yes we can, through the following setup code. First of all an additional dependency for our Maven pom:

<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-apache-client</artifactId>
    <version>1.18.1</version>
</dependency>

For the non-maven users, this adds the following additional dependencies to the project:
  • jersey-apache-client 1.18.1
  • commons-httpclient 3.1
  • commons-logging 1.0.4
  • commons-codec 1.2
With that dependency in place, you can construct the client differently like this:

Client c = ApacheHttpClient.create(clientConfig);

And then you've succesfully plugged in HttpClient in place of the less reliable JDK URLConnection APIs. At this point you may also want to activate automatic cookie handling support which is one of the more useful bonuses that HttpClient gives you:
  ClientConfig clientConfig = new DefaultClientConfig();
  clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
  clientConfig.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);    
  clientConfig.getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES, true); 
  
  Client c = ApacheHttpClient.create(clientConfig);

And that's basically all there is to it; try running whatever test code you have created and you'll see that things still work as they did before. In my experience: a bit faster even. The downside of using HttpClient is that you are of course weighing down your application with even more dependencies.

Dealing with HTTPS

One day this article will have a step-by-step guide on how to not only write the code but also setup a test environment. Until then I defer to this most excellent stackoverflow thread which should be the kick in the right direction that you need:

http://stackoverflow.com/questions/3434309/accessing-secure-restful-web-services-using-jersey-client

Authentication

Authentication can be solved at different levels. First of all there is the API level; the service itself may have some sort of authentication scheme built in, for example requiring you to pass along a HTTP header or certain parameters that identify who is calling. Sending a HTTP header is easy, like this:

    return PROJECT_RESOURCE
            .header("NAME", "VALUE")
            .path(PROJECT_SEARCH + "/" + name)
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .get(new GenericType<List<Project>>() {});

The header() method does all the work. Invoke it multiple times to add more headers.

It may be that the call is actually secured based on IP filtering. Then there is nothing to do with or in code, the firewall of the service provider will either allow or disallow calls from your network. To gain access the firewall needs to be configured appropriately; good luck dealing with tech support.

It may also be that a form of HTTP authentication is employed. Contrary to what the online documentation will try to make you believe, setting up something like basic HTTP authentication through JAX-RS is really as simple as this:

client.addFilter(new HTTPBasicAuthFilter("username", "password"));

And more secure digest authentication:
client.addFilter(new HTTPDigestAuthFilter("username", "password"));

This works just fine with either the "default" Client or the Apache HttpClient.

Finally there is OAUTH, which is an authentication solution and API that has become somewhat of a standard on the net through popularity. Unfortunately I have no experience with using the API just yet so I cannot document it, but some initial scouting on the net seems to indicate that OAUTH support for Jersey is actually available.

Time to call it a day

There you have it. Less than an entire manual on JAX-RS, more than hello world. I hope in this one article I managed to capture the more common use cases for JAX-RS on the client side of things and you are now well on your way to actually being productive. At least I was after having pieced all this stuff together.

For further reading I suggest you get a decent book on the API, but you may also want to check out the JEE 6 tutorial chapter on it, which is likely going to be a slightly less chaotic approach to the material than the Jersey reference manual is but will focus mainly on the programming part. And let me plug my JAX-RS server article one more time :)

Good luck with your project!