13.4 Using XML as a Data Exchange Format


This chapter looks at how XML can be used as a data exchange format (e.g., in files, or over the wire) between JDO-based applications.

13.4.1 Introduction

When using domain-centric data models as described above, there often is a need to represent the data of persistent objects, indeed entire graphs of related persistent objects, in a datastore implementation-independent , externally readable manner.

The purpose of such an external representation is usually interchanging information, and often between systems of different technology, may be using a SOAP-based Web service. However, scenarios like transferring content from one (JDO) datastore to another, or migrating data from one (earlier or different) schema model to another one, equally benefit from a neutral data interchange format. These days, XML is the universally accepted data representation format for many such applications. Various ways exist to write XML data from Java objects (marshaling) and create Java objects by reading XML data (unmarshaling).

13.4.2 Alternatives

In fact, at least one Java persistence framework (Exolab JDO, which is not a Sun JDO API implementation) comes with XML marshaling and unmarshaling abilities straight out of the box and somewhat tied into its API for orthogonal object persistence.

Although the JDO API itself does not offer a built-in XML marshaling and unmarshaling feature, and successfully focuses on binary datastore persistence exclusively, it is relatively easy to achieve if your application requires this. Several possible roads forward exist, and most are based on open -source or freely available XML toolkits, as we see.

Before delving into practice and demonstrating a concrete running example, let us clarify that the next paragraphs are not about how to use JDO with or as an XML database, a database architecture that uses XML structure as native storage format, allowing applications to work transactionally safe with and query possibly large sets of XML data. We are simply going to see how you can marshal and unmarshal persistent JavaBean objects to and from XML, irrelevant of the underlying datastore. However, it is probably only a matter of time until major XML database vendors provide implementations to access their own respective XML datastores using the JDO API.

13.4.3 Available technologies

The savvy Java developer by now will say, "Eh, no big deal, we can put together some code using the JAXP API using SAX or DOM and spit out or process that XML!" That's certainly true, but before you starting hacking away, consider that others have already done this job for you. The possible solutions that we can consider for this purpose are generally termed XML data binding products.

Most XML data binding products fall into two categories:

  • Class generator-like products will generate Java classes based on a DTD or XML Schema. These classes can then be used to marshal object instances to XML documents that comply with the respective DTD or XML schema, and unmarshal XML documents to instances of the generated Java classes.

  • Runtime inspection-based products will attempt to marshal and unmarshal any object complying with the JavaBeans specification to and from XML, without design/compile-time configuration, based on the Java Reflection mechanism.

Other categorizations are possible, notably around questions such as "Can any arbitrary instances be XML serialized?" or "Are XML subtleties such as exact whitespace usage or comments represented (for full object-XML round-tripping) but are of less importance for the purpose of this discussion?" However, the choice between a solution supporting the former or latter of the above approaches is one to make based on the need of your project, because both are equally applicable to JDO-based applications:

  • When using a class generator-like solution, it is usually possible to subsequently enhance the generated classes and use JDO to persist and query instances. In fact, you can achieve a simple home-grown XML database yourself relatively easily.

  • When using a runtime inspection-based solution, a project can use existing persistence-capable classes. These solutions usually require more or less strict JavaBean structure persistent classes, as outlined earlier in this chapter.

Below is a likely non-exhaustive list of some libraries that you may wish to check out. The following are generator-like solutions:

  • Sun JAXB (JSR 31 implementation): At the time of this writing, this solution is still evolving. It is a new Java API, developed under the Java Community Process (JCP) just as JDO was. Early JAXB implementations supported DTDs, and more recent versions are based on XML schemas. At the time of this writing, it is not fully show time yet and it hasn't been for some time, but is still likely where things are going to go in the end.

  • Zeus, from the enhydra.org project.

  • BeanStork, from Zenaptix.

  • Electric XML / XML+, from The Mind Electric.

  • Castor, from Exolab, mentioned just for completeness; Castor is really a mix of persistence framework for relational databases, LDAP repositories, and schema-driven XML marshalling.

These are runtime solutions:

  • JDK 1.4 Long- term bean persistence ( java.beans.XMLEncoder and XMLDecoder ): This is conceptually similar to JDK-standard binary object serialization, and in fact uses a similar API, except that instead of writing an undecipherable byte stream, it serializes to XML. (Developed as JSR 57 and now part of JDK 1.4.)

  • JBind.

  • Quick.

  • Zeus.

  • JiBX.

  • Betwixt from the Apache Jakarta Commons project (see below).

There are many others that are usually fairly similar. The one major difference generally is whether a predefined fixed XML language (tag and field names , and so on) is used, which is the case for JDK 1.4 long-term bean persistence and looks something like the following, which is a non-JDO related example, simply illustrating XML format:

 
 <?xml version="1.0" encoding="UTF-8"?>    <java version="1.0" class="java.beans.XMLDecoder">    <object class="javax.swing.JFrame">      <void property="name">        <string>frame1</string>      </void>      <void property="bounds">        <object class="java.awt.Rectangle">          <int>0</int>          <int>0</int>          <int>200</int>          <int>200</int>        </object>      </void>      <void property="contentPane">        <void method="add">          <object class="javax.swing.JButton">            <void property="label">              <string>Hello</string>            </void>          </object>        </void>      </void>      <void property="visible">        <boolean>true</boolean>      </void>    </object>    </java> 

But if the solution is able to derive an XML language from the JavaBeans fields, usually with more or less configurable mappings, it leads to something like this:

 
 <?xml version="1.0" encoding="UTF-8"?> <book id="2">   <authors>     <author id="3">       <name>Keiron McCammon</name>       <email>mccammon@corejdo.com</email>       <zipCode>10243</zipCode>     </author>     <author id="4">       <email>tyagi@corejdo.com</email>       <name>Sameer Tyagi</name>       <zipCode>31484</zipCode>     </author>     <author id="5">       <name>Michael Vorburger</name>       <email>vorburger@corejdo.com</email>       <zipCode>1234</zipCode>     </author>     <author id="6">       <name>Heiko Bobzin</name>       <email>bobzin@corejdo.com</email>       <zipCode>3391</zipCode>     </author>   </authors>   <price>39.95</price>   <title>Core Java Data Objects Book</title> </book> 

13.4.4 Let's do it

Let's now see some code on how to achieve this in practice. For this example, we are going to use the Betwixt library, a useful little library from the Apache Jakarta Commons project. Betwixt is in beta stage at the time of this writing, but remaining problems are likely to be sorted out rapidly .

As a runtime approach solution, there is no need to write a DTD or an XML schema, or to generate any classes, and so on, as long as our persistent objects are JavaBeans, which the Author and Book classes are. Given a Book instance, jdoBook , with a few Authors associated, the XML snippet shown above is actually as simple to obtain as this line with Betwixt:

 
 BeanWriter beanWriter = new BeanWriter( System.out ); beanWriter.write( jdoBook ); 

Reading a snippet like this could be achieved with a few lines as follows :

 
 BeanReader beanReader = new BeanReader(); beanReader.registerBeanClass( Author.class ); beanReader.registerBeanClass( Book.class ); Book book = (Book)beanReader.parse("book.xml"); 

Betwixt does not require any further initialization or setup code. Although we write to a PrintStream ( System.out ) and read from a filename in the above simple example, Betwixt does also offer an API to write directly to a SAX ContentHandler .

It gets slightly more interesting if you would like to write and read a collection (e.g., JDO Query result) of persistent objects with Betwixt. One way to achieve this with Betwixt is to write a simple container class like the following:

 
 public class BookCollection {     private List books;     public BookCollection() {         books = new LinkedList();     }     public BookCollection(Collection someBooks) {         books = new LinkedList(someBooks);     }     public List getBooks() {         return Collections.unmodifiableList( books );     }     public void addBook(Book _book) {         books.add(_book);     } 

Betwixt (at least the latest version at the time of this writing) requires the addBook(Book book) method to understand that this top-level <BookCollection> contains <Book> objects.

A more complete example scenario could look like this: It creates a few Author and Book objects, with associations from some Books to some Authors. These objects are then persisted in JDO. A real application would get some real work done at this point, and possibly lose references to these objects just created. Then we fire off a JDO Query to find all Book objects. Now we marshal all these objects into an XML representation and store them in a file. Finally, the example reads the file again and compares the unmarshaled Author and Book objects to the original objects.

This simple example implemented using Betwixt or JDK 1.4 long-term bean persistence has several severe limitations:

  • It would not scale well with increasing number of instances, because all XML is held in memory.

  • The JDO datastore identity is lost in the marshaling/unmarshaling. If we had used Application Identity instead of Datastore Identity, this would have come along almost for free.

  • Collection fields with names different from types are not supported without providing extra information to Betwixt, because it uses the method signature to derive the XML element names.

  • Class inheritance of not supported, because Betwixt is unable to map this correctly.

These problems could, however, be addressed by either extending this simple example and/or using other XML data binding technologies.



Core Java Data Objects
Core Java Data Objects
ISBN: 0131407317
EAN: 2147483647
Year: 2003
Pages: 146

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net