News Ticker

Step 2: Marshalling with JAXB

Continuing from the previous article in which I showed how to use an Eclipse wizard to create a web service client given just the URI of the WSDL, I am going to use JAXB, the Java Architecture for XML binding.

Marshalling is mapping XML elements to object properties so that each element of an XML String of data can be ‘injected’ into the properties of an object. Unmarshalling is the opposite. The flattening of an object to an XML String.

1. To get started I am going to create a new package that will contain the classes related to marshalling the XML, I call it demo.webservice.marshal.

Marshalling classes

Marshalling classes

I will need a class that performs the marshalling (StockQuoteMarshaller.java), classes that represent the XML in object form (StockQuotes.java and Stock.java) and a utility class to make the call to the web service (XMLStockQuote.java).

Let’s start with the classes that represent the XML.

The classes that represent the XML in object form will be determined by the structure of the XML, so lets examine the XML.

<StockQuotes>
<Stock>
<Symbol>IBM</Symbol>
<Last>194.93</Last>
<Date>7/5/2013</Date>
<Time>4:00pm</Time>
<Change>+1.68</Change>
<Open>192.83</Open>
<High>195.16</High>
<Low>192.35</Low>
<Volume>2407971</Volume>
<MktCap>216.1B</MktCap>
<PreviousClose>193.25</PreviousClose>
<PercentageChange>+0.87%</PercentageChange>
<AnnRange>181.85 - 215.90</AnnRange>
<Earns>14.501</Earns>
<P-E>13.33</P-E>
<Name>International Bus</Name>
</Stock>
</StockQuotes>

Fortunately the XML is quite simple and consists of a parent element (StockQuotes) that contains one dependent child element (Stock). So I create a class structure representing this relationship. We can represent this in object form as follows.

public class StockQuotes {
  private Stock stock;
}

and the Stock object as follows.

public class Stock {
  private String symbol;
  private String last;
  private String date;
  private String time;
  private String change;
  private String open;
  private String high;
  private String low;
  private String volume;
  private String mktCap;
  private String previousClose;
  private String percentageChange;
  private String annRange;
  private String earns;
  private String pe;
  private String name;
}

As can be seen the StockQuotes object has one dependency the Stock object.

2. Now that we have the class structure created we must create the setters and getters and map the properties in the classes to the elements in the XML.

3. The first task is to map the root element of the class to the root element of the XML. We use @XmlRootElement to map the root element of the class to the root element of the XML, the root element is the class name StockQuotes.

4. Now we continue by mapping the properties in the classes to the elements in the XML using the @XmlElement annotation. In the StockQuote class we annotate the class name as the root element and map the getStock() getter method to the element Stock in the XML.

@XmlRootElement(name="StockQuotes")
public class StockQuotes {

  private Stock stock;

  @XmlElement(name="Stock")
  public Stock getStock() {
    return stock;
  }

  public void setStock(Stock stock) {
    this.stock = stock;
  }
}

Note how I have used a name on each element. This is not strictly necessary if the name of the property is the same as the name of the XML element. I do it here for completeness. Also it is legal to put the annotation on the property instead of the getter method.

5. We do the same with the Stock class and annotate the getter method for each XML element we want to map.

public class Stock {

  private String symbol;
  private String last;
  private String date;
  private String time;
  private String change;
  private String open;
  private String high;
  private String low;
  private String volume;
  private String mktCap;
  private String previousClose;
  private String percentageChange;
  private String annRange;
  private String earns;
  private String pe;
  private String name;

  @XmlElement(name="Symbol")
  public String getSymbol() {
    return symbol;
  }

  public void setSymbol(String symbol) {
   this.symbol = symbol;
  }

  @XmlElement(name="Last")
  public String getLast() {
   return last;
  }

  public void setLast(String last) {
   this.last = last;
  }

  @XmlElement(name="Date")
  public String getDate() {
   return date;
  }

  public void setDate(String date) {
   this.date = date;
  }

  @XmlElement(name="Time")
  public String getTime() {
   return time;
  }

  public void setTime(String time) {
   this.time = time;
  }

  @XmlElement(name="Change")
  public String getChange() {
   return change;
  }

  public void setChange(String change) {
   this.change = change;
  }

  @XmlElement(name="Open")
  public String getOpen() {
   return open;
  }

  public void setOpen(String open) {
   this.open = open;
  }

  @XmlElement(name="High")
  public String getHigh() {
   return high;
  }

  public void setHigh(String high) {
   this.high = high;
  }

  @XmlElement(name="Low")
  public String getLow() {
   return low;
  }

  public void setLow(String low) {
   this.low = low;
  }

  @XmlElement(name="Volume")
  public String getVolume() {
   return volume;
  }
  public void setVolume(String volume) {
   this.volume = volume;
  }

  @XmlElement(name="MktCap")
  public String getMktCap() {
   return mktCap;
  }

  public void setMktCap(String mktCap) {
   this.mktCap = mktCap;
  }

  @XmlElement(name="PreviousClose")
  public String getPreviousClose() {
   return previousClose;
  }

  public void setPreviousClose(String previousClose) {
   this.previousClose = previousClose;
  }

  @XmlElement(name="PercentageChange")
  public String getPercentageChange() {
   return percentageChange;
  }

  public void setPercentageChange(String percentageChange) {
   this.percentageChange = percentageChange;
  }

  @XmlElement(name="AnnRange")
  public String getAnnRange() {
   return annRange;
  }

  public void setAnnRange(String annRange) {
   this.annRange = annRange;
  }

  @XmlElement(name="Earns")
  public String getEarns() {
   return earns;
  }
  public void setEarns(String earns) {
   this.earns = earns;
  }
  @XmlElement(name="P-E")
  public String getPe() {
   return pe;
  }

  public void setPe(String pe) {
   this.pe = pe;
  }

  @XmlElement(name="Name")
  public String getName() {
   return name;
  }

  public void setName(String name) {
   this.name = name;
  }

 }

We have a small problem with the XML element named p-e because the hypen is not legal in the name of a java property but the property must have the same name as the XML element. The solution to the is to name the XmlElement using the name of the XML element and give the java property a legal name. So we have the following

@XmlElement(name="P-E")
public String getPe() {
  return pe;
}

6. That’s the hard part over. To finish we need two more classes. One class to marshal (or unmarshal in this case as we transform from XML to object) and another to call the webservice code from step 1 and returns the XML.

I will write the unmarshalling method as static because it is a utility method that we call to perform a function.

Create a new class called StockQuoteMarshalling.java with the following code.

public static Stock unmarshal(String xml) {

  JAXBContext jc;
  Stock stock = null;

  try {

    JAXBContext jaxbContext = JAXBContext.newInstance(StockQuotes.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    StockQuotes retr = (StockQuotes) jaxbUnmarshaller.unmarshal(new StringReader(xml));
    stock = retr.getStock();

 } catch (JAXBException e) {
    e.printStackTrace();
  }

  return stock;
}

Now for the utility method that calls the webservice code from step 1 and returns the XML. Create a class XMLStockQuote.java with the following code. The getXMLForCode accepts a stock as the only parameter. This code originates from the request object processed by the servlet (which we create in step 3).

public static String getXMLForCode(String code) {

  String quote = "";
  try {
    quote = new StockQuoteLocator().getStockQuoteSoap().getQuote(code);
  } catch (RemoteException | ServiceException e) {
    e.printStackTrace();
  }

  return quote;
}

Now we need to create the servlet and JSP template.

Leave a Reply