JAXB's workings and the associated development process are best understood through an example. We will quickly walk though an example and then look at different aspects of JAXB from that example in detail.
OfficeMin can receive purchase orders in many ways. In Chapter 11, we saw how a customer such as Flute Bank can use JAXM to send XML messages. Another customer, Piggy Bank, uses a proprietary financial package but is capable of generating and saving purchase order details in XML format. OfficeMin's Web service can process these XML orders.
The first step for OfficeMin to consume the XML is to generate the Java representation of the agreed-upon schema. We will use the schema covered in Chapter 11 and shown in Listing 13.1.
The JAXB specifications require that all JAXB implementations provide a tool called a schema compiler or binding compiler (Figure 13.2), which should be able to generate the Java code according to the rules and guidelines defined in the JAXB specification. In the reference implementation provided by Sun, the tool is called the XML-to-Java compiler (xjc).
Execute the schema compiler on the purchase order interface:
xjc-d output generated purchaseorder.xsd
This will generate two sets of files:
Interfaces that correspond to the XML elements according to the mapping rules defined in JAXB (e.g., PurchaseOrder.java, Billingaddress.java, State.java, Street.java) in a com.flutebank.schema. package. We will discuss this in the next section.
Implementation classes for the interfaces that are specific to the JAXB runtime. (e.g., PurchaseOrderImpl.java, BillingaddressImpl.java, StateImpl.java) in a com.flutebank.schema.impl package.
The application in the example reads in an XML file and does something useful (for now, it just changes some information around) and writes out an XML file. The file we will read in, purchaseorder.xml, was used in Chapter 9.
import java.io.*; import java.util.*; // import JAXB API import javax.xml.bind.*; // import java content classes generated by binding compiler import com.flutebank.schema.*; public class ReadWritePO { public static void main( String[] args ) throws Exception { // create a JAXBContext capable of handling classes in the generated package JAXBContext context = JAXBContext.newInstance( "com.flutebank.schema" ); // create an Unmarshaller Unmarshaller unmars = context.createUnmarshaller(); // unmarshall an XML document into its Java representation Purchaseorder po = (Purchaseorder)unmars.unmarshall( new FileInputStream( "purchaseorder.xml" ) ); // display the shipping address Billingaddress address = po.getBillingaddress(); Name name= address.getName(); Street street= address.getStreet(); City city= address.getCity(); State state = address.getState(); Zip zip= address.getZip(); System.out.println( "Billing address in the XML is : " ); System.out.println("Name :" + name.getValue()); System.out.println("Street :" + street.getValue()); System.out.println("City :" + city.getValue()); System.out.println("State :" + state.getValue()); System.out.println("Zip :" + zip.getValue()); Items order=po.getItems(); Iterator it=order.getItem().iterator(); while(it.hasNext()){ Item item= (Item)it.next(); System.out.println("Order contains" ); System.out.println(" Description: " + item.getDescription().getValue()); System.out.println(" Product number: " + item.getProductnumber().getValue()); System.out.println(" Quantity: " + item.getQuantity().getValue()); System.out.println(" Unit cost: " + item.getUnitcost().getValue()); } // Change some information name.setValue("Sameer Tyagi"); zip.setValue("90210"); // Marshall Java to XML Marshaller mars = context.createMarshaller(); mars.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE ); mars.setProperty (Marshaller.JAXB_SCHEMA_LOCATION," http://www.flutebank.com/schema purchaseorder.xsd"); mars.marshall( po, new FileOutputStream("modifiedpurchaseorder.xml")); } }
It should be apparent that the code in Listing 13.1 does not involve any parsing logic whatsoever. The application code uses the JAXB API (e.g., Unmarshaller and JAXBContext) when dealing with the marshalling and unmarshalling and uses the generated interfaces when dealing with the object representation. Listing 13.3 shows the output saved in modifiedpurchaseorder.xml.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns1:purchaseorder xsi:schemaLocation="http://www.flutebank.com/schema purchaseorder.xsd" xmlns:ns1="http://www.flutebank.com/schema" xmlns:xsi="http:// www.w3.org/2001/XMLSchema-instance"> <ns1:identifier>87 6784365876JHITRYUE</ns1:identifier> <ns1:date>29 October 2002</ns1:date> <ns1:billingaddress> <ns1:name>Sameer Tyagi</ns1:name> <ns1:street>256 Eight Bit Lane</ns1:street> <ns1:city>Burlington</ns1:city> <ns1:state>MA</ns1:state> <ns1:zip>90210</ns1:zip> </ns1:billingaddress> <ns1:items> <ns1:item> <ns1:quantity>3</ns1:quantity> <ns1:productnumber>229AXH</ns1:productnumber> <ns1:description>High speed photocopier machine with automatic sensors </ns1:description> <ns1:unitcost>1939.99</ns1:unitcost> </ns1:item> <ns1:item> <ns1:quantity>1</ns1:quantity> <ns1:productnumber>1632</ns1:productnumber> <ns1:description>One box of color toner cartridges</ns1:description> <ns1:unitcost>43.95</ns1:unitcost> </ns1:item> </ns1:items> </ns1:purchaseorder>
The preceding example should have helped clarify how JAXB works and the simplified approach it provides to developers. No more parsing! Looking at Listing 13.1, it should also be apparent that it has two parts:
Code generated using the binding compiler that binds XML schemas to Java types
Code that uses API defined in the JAXB specifications and deals with Java-XML marshalling and unmarshalling
Let us now look at the underpinnings of JAXB in these two areas.