Using JAXB
Creating JAXB beans
For this example, we'll work with a set of JAXB bean that are
generated from an existing XML Schema document. The example below
provides a sample schema document for a stock quote service. There is
only one xml element defined, which includes the stock price and the
company name and ticker symbol.
To generate a set of JAXB beans from this schema, you will need
to run the "xjc" tool that is provided with the JDK (available in Java
6). Passing the schema document as a parameter, this should generate a
set of java classes including one for the Stock and one of the
StockQuote types.
Once you have generated the beans, you're ready to move on to the
next step; building the stock quote JAX-RS resource.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns="http://ibm.com/sample/jaxrs"
targetNamespace="http://ibm.com/sample/jaxrs">
<xsd:element name="stockQuote">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="stock" type="ns:Stock" />
<xsd:element name="quote" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Stock">
<xsd:sequence>
<xsd:element name="symbol" type="xsd:string" />
<xsd:element name="price" type="xsd:float" />
<xsd:element name="companyName" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
|
Adding JAXB beans to resources
JAXB beans can be included either as parameters to the request or
the return type of a methods. For the purposes of simplicity, let's
start by returning a JAXB from a resource method. The code below is an
example of how to implement the StockQuoteService resource method. The
method will return the StockQuote bean that corresponds to the stock
symbol in the path parameter.
This resource can be packaged and deployed as a JAX-RS resource
using the instructions found here.
package com.ibm.sample.jaxrs;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import java.util.HashMap;
import java.util.Map;
@Path(value="/stocks")
public class StockQuoteService {
private static Map<String , StockQuote> stocks = new HashMap<String
, StockQuote>();
static {
Stock s = new Stock();
s.setCompanyName("IBM");
s.setSymbol("IBM");
StockQuote quote = new StockQuote();
quote.setQuote(98.99);
quote.setStock(s);
stocks.put(s.getSymbol(), quote);
s = new Stock();
s.setCompanyName("Yahoo!");
s.setSymbol("YHOO");
quote = new StockQuote();
quote.setQuote(23.18);
quote.setStock(s);
stocks.put(s.getSymbol(), quote);
}
@GET
@Path(value="/{symbol}")
@Produces(value="application/xml")
public StockQuote getQuote(@PathParam(value="symbol") String symbol) {
System.out.println("[stockquote] - looking up quote for symbol " + symbol);
StockQuote quote = stocks.get(symbol);
System.out.println("[stockquote] - returning value: " + quote);
return quote;
}
}
|
Creating a client
Once deployed, the newly created resource can be accessed from a
browser using this URL:
http://<hostname>:<port>/<context
root>/stocks/{stock symbol}
For this example, we'll provide some concrete values to those
variables. We'll use:
http://localhost:9080/stockquote/stocks/IBM
However, it is more useful to access this resource from a more
robust client. One way to do this is using the Apache Commons HTTP
Client API. More information about how to write clients using this API
can be found here.
The code sample below shows how to access this resource and
retreive the information using JAXB. Notice that an InputStream is
returned from the resource and the client passes that directly to the
JAXB Umarshaller API. Based on the configuration provided, JAXB will
return the appropriate object type.
package com.ibm.sample.jaxrs;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
public class StockQuoteClient {
private String url = "http://localhost:9080/stockquote/stocks/";
private JAXBContext ctx;
public static void main(String[] args) throws Exception {
StockQuoteClient client = new StockQuoteClient();
client.getQuote("IBM");
}
public void getQuote(String symbol) throws Exception {
HttpClient client = new HttpClient();
GetMethod get = new GetMethod(url + symbol);
int responseCode = client.executeMethod(get);
System.out.println("[getquote] - response code: " + responseCode);
JAXBContext ctx = JAXBContext.newInstance("com.ibm.sample.jaxrs");
Unmarshaller u = ctx.createUnmarshaller();
InputStream is = get.getResponseBodyAsStream();
StockQuote quote = (StockQuote) u.unmarshal(is);
if (quote != null) {
System.out.println("[getquote] - " + quote.getStock().getSymbol()
+ " = " + quote.getQuote());
}
}
}
|
Sending JAXB data from the client
Now that you know how to receive the JAXB data, try sending JAXB
data to the server using the HTTP POST method. See if you can follow the
code samples below to create a JAXB object instance and send the data
using the Apache client so that a new stock symbol is added to the
quotes database.
To do this, the first thing you'll need is the actual resource
method. Here's an example of what this would look like. Notice that this
is a method with a void response and the JAXB parameter for the input.
Try adding this to your existing StockQuoteService and redeploy the
service in your environment.
@POST
@Consumes(value="application/xml")
public void addQuote(StockQuote q) {
stocks.put(q.getStock().getSymbol(), q);
}
|
Now add a method to the client that will target the new resource
method. Notice that instead of creating an Umarshaller to get the data
out of the stream for JAXB, this time we're creating a Marshaller and
putting the data into a stream. The contents of the stream are then put
into a RequestEntity object which also requires that the HTTP
Content-Type header be set. Invoking this method will send your data to
the server and add a new stock type to the database.
public int addQuote(String company, String symbol, double price)
throws Exception {
ObjectFactory of = new ObjectFactory();
Stock s = of.createStock();
s.setCompanyName(company);
s.setSymbol(symbol);
StockQuote q = of.createStockQuote();
q.setQuote(price);
q.setStock(s);
JAXBContext ctx = JAXBContext.newInstance("com.ibm.sample.jaxrs");
Marshaller m = ctx.createMarshaller();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
m.marshal(q, baos);
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url);
RequestEntity request = new ByteArrayRequestEntity(baos.toByteArray(),
"application/xml; charset=utf-8");
post.setRequestEntity(request);
int responseCode = client.executeMethod(post);
System.out.println("[addquote] - response code: " + responseCode);
return responseCode;
}
|
The next step is to update the client code to call the new
method. Here's a sample of how to to this. Once the addQuote method is
called, you should be able to access the new resource via the getQuote
method.
public static void main(String[] args) throws Exception {
StockQuoteClient client = new StockQuoteClient();
client.getQuote("IBM");
client.addQuote("Microsoft", "MSFT", 22.45);
client.getQuote("MSFT");
}
|
After making all of the updates, the output of the client should
look like the following:
[getquote] - response code: 200
[getquote] - IBM = 98.99
[addquote] - response code: 200
[getquote] - response code: 200
[getquote] - MSFT = 22.45
|
Take the next step
Now see if you can take it one step further by adding a resource
method that updates the stock price using the HTTP PUT method. Remember,
you'll need to add a resource method annotated with @PUT along with new
client code for invoking this method. The resource method signature
should be similar to the addQuote signature, but this method will just
updated the price of the stock. Good luck!