Home | | Service Oriented Architecture | Java Architecture for XML Binding (JAXB)

Chapter: XML and Web Services : Building XML-Based Applications : Parsing XML Using Document Object Model

Java Architecture for XML Binding (JAXB)

JAXB provides a means of automatically binding XML with Java objects. JAXB is being developed through the Java Community Process (JCP) under JSR-31.

Java Architecture for XML Binding (JAXB)

 

JAXB provides a means of automatically binding XML with Java objects. JAXB is being developed through the Java Community Process (JCP) under JSR-31. The home of JAXB is http://java.sun.com/xml/jaxb/index.html.

 

JAXB can be considered a serialization mechanism from Java objects to XML. Serialization is the process of converting an object in memory into a stream of data, and vice versa. Serialization is a convenient way of storing objects on disk or sending them over a network. Object serialization based on serializable and externalizable interfaces performs a similar function but requires the developer to simply implement one of these interfaces. In the case of JAXB, a set of binding classes is generated using a schema compiler. The classes manage marshalling, meaning translating Java objects to XML and back again. Here is a brief summary of some of benefits of JAXB:

 

   Valid data is guaranteed. Marshalling is based on a schema, which constrains the structure of the XML.

 

   JAXB is faster and requires less memory when compared with DOM. DOM includes a lot of functionality for manipulating arbitrary documents. JAXB applications are specific to a given schema, so they can be more efficient.

 

   JAXB is relatively easy to use. All you need to do is supply a schema and generate binding classes using a schema compiler. From there, reading, writing, and modify-ing XML is simply a matter of a few method calls.

 

   JAXB applications are extensible. The generated classes can be used as is, or they can be subclassed for reusability and added functionality.

 

Data Binding

 

If you think about it, a class and a schema perform similar functions. Classes describe Java objects, whereas schemas describe XML documents. An object is an instance of a class, and a document follows a schema. The diagram in Figure 7.3 illustrates the rela-tionships between schemas, classes, documents, and objects.

 


If we have a schema, perhaps in the form of a DTD, we can automatically generate classes that translate between objects and documents. Of course, in the real world, we might want to customize some of the details of the generated classes. Fortunately, JAXB provides facilities for customization through an optional binding schema.

One way to define a binding is to generate one Java class for every element in a schema. If you don’t provide any extra information, this is basically what JAXB does. Attributes within an element are mapped to String fields. Content within an element is a little more complicated. Table 7.6 summarizes how the content is mapped within a Java class.

 

TABLE 7.6     Default Content Binding


JAXB Example

 

Let’s look at an example using JAXB. A sample DTD is shown in Listing 7.16. We will use this DTD as our schema for generating binding classes. As of this writing, the JAXB schema compiler only accepts DTDs. In the future, other schema formats may be accepted.

 

LISTING 7.16  library.dtd

 

<?xml version=”1.0” encoding=”US-ASCII”?>

<!ELEMENT library (fiction|biography|science)*>

<!ELEMENT fiction (book)+>

 

<!ELEMENT biography (book)+>

<!ELEMENT science (book)+>

<!ELEMENT book (#PCDATA)>

<!ATTLIST  book  author  CDATA  #REQUIRED>

 

This DTD describes a simple library with three categories of books: fiction, biography, and science. Each of these categories can contain one or more book elements. Each book element contains an author attribute, and the title will be defined in the content of the book element. This isn’t necessarily a practical example, but it will give you a good idea how JAXB works. It can be easily expanded as needed.

 

In order to generate binding classes, we need to run the schema compiler shipped with JAXB. The schema compiler is itself written in Java and can be invoked like this:

 

java  com.sun.tools.xjc.Main  -d  outdir  -roots  library  library.dtd

 

Of course, the schema compiler JAR file must be in your classpath (dropping the JAR into your JDK/jre/lib/ext directory is the simplest way). The -d option specifies an output directory for the generated classes. If it’s not included, the current directory is used. The -roots option specifies a comma-separated list of root elements. This is needed because DTDs don’t provide a way to define root elements. The last argument is the filename of our DTD.

 

The schema compiler can also accept an optional binding schema. The binding schema is an XML file with the extension .xjs. It can include information such as the root ele-ments, names of classes and methods, which elements to bind to classes, types for attrib-utes, and data conversions. If you specify a binding schema, you can avoid the -roots option. If you don’t use a binding schema, you must supply the -roots option. There’s quite a bit you can do with binding schemas, so it’s best to refer to the JAXB specifica-tion to get it all. We will stick with the default bindings provided automatically with the schema compiler. In many cases, this is good enough.

 

Once the schema compiler is run on our sample DTD, five Java source files are gener-ated containing the classes that describe each of the elements in library.dtd. The code for the root element, Library.java, is shown in Listing 7.17.

 

LISTING 7.17  Library.java

 

//  imports  not  shown

 

public  class  Library

 

extends MarshallableRootElement implements RootElement

 

{

 

private List _Content = PredicatedLists.createInvalidating(this, new ContentPredicate(), new ArrayList());

 

private  PredicatedLists.Predicate  pred_Content  =  new  ContentPredicate();

 

public List getContent() { return _Content;

 

}

 

public void deleteContent() { _Content = null; invalidate();

 

}

 

public  void  emptyContent()  {

 

_Content = PredicatedLists.createInvalidating(this, pred_Content, new ArrayList());

 

}

LISTING 7.17   continued

 

public  void  validateThis()

 

throws  LocalValidationException

 

{

 

}

 

public void validate(Validator v) throws StructureValidationException

 

{

 

for (Iterator i = _Content.iterator(); i.hasNext(); ) {

v.validate(((ValidatableObject) i.next()));

 

}

 

}

 

public void marshal(Marshaller m) throws IOException

 

{

 

XMLWriter w = m.writer(); w.start(“library”);

 

if  (_Content.size()>  0)  {

 

for (Iterator i = _Content.iterator(); i.hasNext(); ) { m.marshal(((MarshallableObject) i.next()));

 

}

 

}

 

w.end(“library”);

 

}

 

public void unmarshal(Unmarshaller u) throws UnmarshalException

 

{

 

XMLScanner xs = u.scanner(); Validator v = u.validator(); xs.takeStart(“library”); while (xs.atAttribute()) {

 

String an = xs.takeAttributeName(); throw new InvalidAttributeException(an);

 

}

 

{

 

List l = PredicatedLists.create(this, pred_Content, new ArrayList());

 

while ((xs.atStart(“fiction”)||xs.atStart(“biography”))|| xs.atStart(“science”)) {

 

l.add(((MarshallableObject)  u.unmarshal()));

 

}

 

_Content = PredicatedLists.createInvalidating(this, pred_Content, l);

 

}

 

xs.takeEnd(“library”);

 

}

public static Library unmarshal(InputStream in) throws UnmarshalException

 

{

 

return  unmarshal(XMLScanner.open(in));

 

}

 

public static Library unmarshal(XMLScanner xs) throws UnmarshalException

 

{

 

return  unmarshal(xs,  newDispatcher());

 

}

 

public static Library unmarshal(XMLScanner xs, Dispatcher d) throws UnmarshalException

 

{

 

return  ((Library)  d.unmarshal(xs,  (Library.class)));

 

}

 

public boolean equals(Object ob) { if (this == ob) {

 

return  true;

 

}

 

if (!(ob instanceof Library)) { return false;

 

}

 

Library tob = ((Library) ob); if (_Content!= null) {

 

if (tob._Content == null) { return false;

 

}

 

if (!_Content.equals(tob._Content)) { return false;

 

}

 

}  else  {

 

if (tob._Content!= null) { return false;

 

}

 

}

 

return  true;

 

}

 

public int hashCode() { int h = 0;

 

h = ((127 *h)+((_Content!= null)?_Content.hashCode(): 0)); return h;

 

}

 

public  String  toString()  {

 

StringBuffer  sb  =  new  StringBuffer(“<<library”);

LISTING 7.17  continued

 

if (_Content!= null) { sb.append(“ content=”);

 

sb.append(_Content.toString());

 

}

 

sb.append(“>>”); return sb.toString();

 

}

 

public static Dispatcher newDispatcher() { return Biography.newDispatcher();

 

}

 

private static class ContentPredicate implements PredicatedLists.Predicate

 

{

 

public  void  check(Object  ob)  {

 

if (!(ob instanceof MarshallableObject)) { throw new InvalidContentObjectException(ob,

 

(MarshallableObject.class));

 

}

 

}

 

}

 

}

 

There is a field named _Content of type java.util.List. This object can contain any number of elements—specifically, the categories of books in our library. A List object is used for the content because we didn’t specify a particular type in a binding schema. In this case, the schema compiler chose a List object because our library element can con-tain a variable number of sub-elements. There are a few validation methods that can vali-date this class and all content. The marshal() and unmarshal() methods read and write XML to and from streams.

 

A simple application that exercises the generated classes is shown in Listing 7.18. This application reads an XML file, adds another book element, validates the XML, and writes all the content to a second XML file. This is typical of the kinds of applications that can be developed with JAXB.

 

LISTING 7.18  LibraryApp.java

 

import java.io.*; import java.util.*; import javax.xml.bind.*;

 

import  javax.xml.marshal.*;

public class LibraryApp { protected Library myLibrary;

 

public LibraryApp() { myLibrary = new Library();

 

}

 

public static void main(String[] args) throws Exception { LibraryApp la = new LibraryApp();

 

la.readXML(“library.xml”);

 

la.addBook();

 

la.validate(); la.writeXML(“new_library.xml”);

 

}

 

public void readXML(String fileName) throws Exception { System.out.println(“Reading “ + fileName); FileInputStream fIn = new FileInputStream(fileName); try {

 

myLibrary = myLibrary.unmarshal(fIn); } finally {

 

fIn.close();

 

}

 

System.out.println(myLibrary);

 

}

 

public  void  addBook()  {

 

List  entryList  =  myLibrary.getContent();

 

for (ListIterator i = entryList.listIterator(); i.hasNext();) { Object element = i.next();

 

if (element instanceof Science) { Book qmBook = new Book();

 

qmBook.setAuthor(“Eisberg, Resnick”); qmBook.setContent(“Quantum Mechanics”); Science sb = (Science) element;

 

List sl = sb.getBook(); sl.add(qmBook);

 

break;

 

}

 

}

 

}

 

public void validate() throws Exception { myLibrary.validate();

 

}

 

public void writeXML(String fileName) throws Exception { System.out.println(“Writing “ + fileName);

LISTING 7.18  continued

 

FileOutputStream fOut = new FileOutputStream(fileName); try {

 

myLibrary.marshal(fOut); } finally {

 

fOut.close();

 

}

 

}

 

}

 

The two imported packages of interest are javax.xml.bind and javax.xml.marshal. The first one, javax.xml.bind, contains most of the classes for JAXB. The second pack-age, javax.xml.marshal, contains a few classes needed for marshalling. These classes were split into two packages because marshalling is not specific to XML. There could be marshalling classes for all kinds of data bindings.

 

The readXML() method reads an XML file into a Library object using the unmarshal() method. This could throw an UnmarshalException caused by invalid XML.

 

The addBook() method obtains a reference to the content of the Library object as a List object. It then searches for a category of type science, creates a book object, and adds it to the science category. Notice the setAuthor() method defined in the Book class. This was also generated by the schema compiler.

 

The validate() method validates the Library object before it is written using the writeXML() method. Validation is required if any of the objects describing our document were modified. If validation is not done, an exception would be thrown by the marshal() method.

 

As you can see, JAXB is fairly easy to use. A lot of functionality can be added automati-cally by specifying a binding schema. As mentioned earlier, you might want to explore binding schemas in detail to get the most out of JAXB.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Let’s take a look at a case study so you can see how DOM works in the real world. We will build a Java servlet that accepts a SQL statement to query a database and returns the results in the form of XML. This might seem like overkill. Why not just connect to the database through ODBC or JDBC and obtain a result set? Of course, you could do that, but there are firewall con-straints and possibly the need for a persistent connection to the client. HTTP is a simple protocol that any firewall will pass without complaining. HTTP is easy to implement and easy to debug. Most importantly, it’s an open protocol with wide industry support.

 

What we will end up with is something like an XML data server. Of course, com-mercial-quality data servers do a lot more, such as manage scalability through caching and load balancing. Even still, we can build an effective data server for illustration purposes, and scalability can be addressed later.

 

A servlet accepts a request from a client and returns results in XML. The servlet acts as the “glue” between the Internet and the database. Figure 7.4 illustrates the operation of the servlet and database.


It would be nice to automate as much of the XML generation as possible. What we can do is use the column names of the database result set as the element names of our XML output. We can use ResultSetMetaData from JDBC to give us this information. The source code for our XML servlet is shown in Listing 7.19.

 

The complete source code is available on the Sams Web site. Our sample data-base contains information from the 2000 CIA World Fact Book. In order to experiment with XMLServlet, you will need a servlet engine such as Apache Tomcat. Tomcat is freely available for download from http://Jakarta.apache.org/tomcat. The download includes detailed installa-tion instructions along with a number of examples. You can use almost any database for testing. Any one of the sample databases supplied with Microsoft Access will work well.

 

Sample output is shown in Listing 7.20.

 

LISTING 7.19  XMLServlet.java

 

package  com.madhu.xml;

 

import java.io.*; import java.util.*; import java.sql.*;

import javax.servlet.*; import javax.servlet.http.*;

 

import  org.jdom.*;

 

import  org.jdom.output.*;

 

public class XMLServlet extends HttpServlet { protected Connection connection;

 

public void init() { try {

 

Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); connection = DriverManager.getConnection(

 

“jdbc:odbc:worldfactbook”); } catch (Exception e) {

 

e.printStackTrace();

 

}

 

}

 

public  void  doGet(HttpServletRequest  request,

 

HttpServletResponse  response)  throws  IOException  {

 

ServletConfig config = getServletConfig(); PrintWriter out = response.getWriter(); response.setContentType(“text/xml”);

 

try  {

 

String sql = request.getParameter(“sql”); Statement stat = connection.createStatement(); ResultSet rs = stat.executeQuery(sql); ResultSetMetaData rsMeta = rs.getMetaData(); int rowNumber = 1;

 

Element root = new Element(“resultset”); root.setAttribute(“query”, sql);

 

while  (rs.next())  {

 

Element row = new Element(“row”);

row.setAttribute(“index”,

Integer.toString(rowNumber));

int nCols = rsMeta.getColumnCount();

 

for  (int  i=1;  i<=nCols;  i+=1)  {

 

String colName = rsMeta.getColumnName(i);

Element column = new Element(colName);

column.addContent(rs.getString(i));

row.addContent(column);

 

}

 

root.addContent(row); rowNumber += 1;

 

}

 

rs.close();

 

stat.close();

 

Document  doc  =  new  Document(root);

 

XMLOutputter outputter = new XMLOutputter(“\t”, true);

outputter.output(doc, out);

 

} catch (Exception e) { e.printStackTrace(out);

 

}

 

}

 

}

 

 

LISTING 7.20  XMLServlet Sample Output

 

<?xml  version=”1.0”  encoding=”UTF-8”?>

 

<resultset query=”select * from people where country like ‘united%’”> <row index=”1”>

 

<ID>220</ID>

 

<Country>United Arab Emirates</Country>

<Population>2369153.0</Population>

<GrowthRate>1.61</GrowthRate>

<BirthsPer1000>18.0</BirthsPer1000>

<DeathsPer1000>3.68</DeathsPer1000>

<NetMigrationPercent>1.82</NetMigrationPercent>

<NetMigration>43118.5846</NetMigration>

<InfantMortalityPer1000>17.17</InfantMortalityPer1000>

<TotalLifeExpectency>74.06</TotalLifeExpectency>

<MaleLifeExpectency>71.64</MaleLifeExpectency>

<FemaleLifeExpectency>76.61</FemaleLifeExpectency>

 <TotalLiteracy>79.2</TotalLiteracy>

 <MaleLiteracy>78.9</MaleLiteracy>

<FemalLiteracy>79.8</FemalLiteracy>

 

</row>

 

<row index=”2”> <ID>221</ID>

 

<Country>United Kingdom</Country>

<Population>59511464.0</Population>

<GrowthRate>0.25</GrowthRate>

<BirthsPer1000>11.76</BirthsPer1000>

<DeathsPer1000>10.38</DeathsPer1000> <NetMigrationPercent>1.07</NetMigrationPercent>

 <NetMigration>636772.6648</NetMigration>

 <InfantMortalityPer1000>5.63</InfantMortalityPer1000>

<TotalLifeExpectency>77.66</TotalLifeExpectency>

 

<MaleLifeExpectency>74.97</MaleLifeExpectency>

 

<FemaleLifeExpectency>80.49</FemaleLifeExpectency>

 

<TotalLiteracy>99.0</TotalLiteracy>

 

<MaleLiteracy>0.0</MaleLiteracy>

 

<FemalLiteracy>0.0</FemalLiteracy>

 

</row>

 

<row index=”3”> <ID>222</ID>

 

<Country>United States</Country>

<Population>275562673.0</Population>

<GrowthRate>0.91</GrowthRate>

<BirthsPer1000>14.2</BirthsPer1000>

<DeathsPer1000>8.7</DeathsPer1000>

<NetMigrationPercent>3.5</NetMigrationPercent>

<NetMigration>9644693.555</NetMigration>

<InfantMortalityPer1000>6.82</InfantMortalityPer1000>

<TotalLifeExpectency>77.12</TotalLifeExpectency>

<MaleLifeExpectency>74.24</MaleLifeExpectency>

<FemaleLifeExpectency>79.9</FemaleLifeExpectency>

<TotalLiteracy>97.0</TotalLiteracy>

<MaleLiteracy>97.0</MaleLiteracy>

<FemalLiteracy>97.0</FemalLiteracy>

 

</row>

 

</resultset>

 

As in any servlet, the bulk of the work is performed in the goGet() method. The doGet() method will only be called in response to a GET request. If responses to both GET and POST requests are necessary, you can override the service() method instead.

 

The SQL query is supplied as part of the query string. We can obtain this string using the getParameter() method while supplying the name of the parameter. In our example, the parameter name is simply sql. Once we have the SQL, we can issue standard JDBC calls to obtain a result set.

 

Now the interesting part begins. We will use JDOM to create the DOM tree. As you saw earlier, JDOM can be easier to use when creating a document. The result set is translated into a DOM tree by using the ResultSet column names as element names. The column names are obtained through ResultSetMetaData. The resulting DOM tree is written to the response output stream using XMLOutputter.

 

 

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail
XML and Web Services : Building XML-Based Applications : Parsing XML Using Document Object Model : Java Architecture for XML Binding (JAXB) |


Privacy Policy, Terms and Conditions, DMCA Policy and Compliant

Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.