BUY THIS BOOK
Add to Cart

Print Book $34.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £24.95

What is this?

Looking to Reprint this content?


Java & XML Data Binding
Java & XML Data Binding

By Brett McLaughlin
Price: $34.95 USD
£24.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introduction
With the wealth of interest in XML in the last few years, developers have begun to crave more than the introductory books on XML and Java that are currently available. While a chapter or two on SAX, some basic information on JAXP, and a section on web services was sufficient when these APIs were developed, programmers now want more. Specifically, there is a huge amount of interest in XML data binding, a new set of APIs that allows XML to be dealt with in Java simply and intuitively, without worrying about brackets and syntactical issues. The result is a need in the developer community for an extensive, technically focused documentation set on using data binding; examples are no longer just helpful, but a critical, required part of this documentation set. This book will provide that technical documentation, ready for immediate use in your application programming.
To fill this need, I want to start off on the right foot and dive into some technical material. This chapter will give you basic information about existing XML APIs and how they relate to XML data binding. From there, I move on to the four basic facets of data binding, which the first half of this book focuses on. Finally, to get you ready for the extensive examples I walk you through, I devote the last portion of this chapter to the APIs, projects, and tools you'll need throughout the rest of the book. From there on, I assault you with examples and technical details, so I hope you're ready.
By the simple fact that you've picked up this book, I assume that you are interested in working with XML from within your Java programs and applications. However, it's probably not too smart to assume that you're a Java and XML expert (yet—although picking up my Java and XML book could help!), so I want to take you through the application programming interfaces (APIs) available for working with XML from Java. I'll start by detailing what I will henceforth refer to as low-level APIs. These APIs allow you direct access to an XML document's data
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Low-Level APIs
By the simple fact that you've picked up this book, I assume that you are interested in working with XML from within your Java programs and applications. However, it's probably not too smart to assume that you're a Java and XML expert (yet—although picking up my Java and XML book could help!), so I want to take you through the application programming interfaces (APIs) available for working with XML from Java. I'll start by detailing what I will henceforth refer to as low-level APIs. These APIs allow you direct access to an XML document's data, as well as its structure.
To illustrate this concept a little more clearly, consider the following simple XML document:
<?xml version="1.0"?>
  
<songs>
  <song>
    <title>The Finishing Touch</title>
    <artist type="Band">Sound Doctrine</artist>
  </song>
  
  <song>
    <title>Change Your World</title>
    <artist type="Solo">Eric Clapton</artist>
    <artist type="Solo">Babyface</artist>
  </song>
  
  <song>
    <title>The Chasing Song</title>
    <artist type="Band">Andy Peterson</artist>
  </song>
</songs>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
High-Level APIs
So far, the APIs I've discussed have been driven by the data in an XML document. They give you flexibility and power, but also generally require that you write more code to access that power. However, XML has been around long enough that some pretty common use cases have begun to crop up. For example, configuration files are one of the most common uses of XML around. Here's an example:
<?xml version="1.0"?>
  
<ejb-jar>
  <entity>
    <description>This is the Account EJB which represents
    the information which is kept for each Customer</description>
  
    <display-name>TheAccount</display-name>
    <ejb-name>TheAccount</ejb-name>
    <home>com.sun.j2ee.blueprints.customer.account.ejb.AccountHome</home>
    <remote>com.sun.j2ee.blueprints.customer.account.ejb.Account</remote>
    <ejb-class>com.sun.j2ee.blueprints.customer.account.ejb.AccountEJB</ejb-class>
    <persistence-type>Bean</persistence-type>
    <prim-key-class>java.lang.String</prim-key-class>
    <reentrant>False</reentrant>
    <env-entry>
      <env-entry-name>ejb/account/AccountDAOClass</env-entry-name>
      <env-entry-type>java.lang.String</env-entry-type>
      <env-entry-value>
        com.sun.j2ee.blueprints.customer.account.dao.AccountDAOImpl
      </env-entry-value>
    </env-entry>
  
    <resource-ref>
      <res-ref-name>jdbc/EstoreDataSource</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
    </resource-ref>
  </entity>
</ejb-jar>
In this case, the example is a deployment descriptor from Sun's PetStore J2EE example application. Here, there isn't any data processing that needs to occur; an application that deploys this application wants to know the description, the display name, the home interface, and the remote interface. However, you can see that these are simply the names of the various elements.
Instead of spending time parsing and traversing, it would be much easier to code something like this:
List entities = ejbJar.getEntityList(  );
for (Iterator i = entities.iterator(); i.hasNext(  ); ) {
    Entity entity = (Entity)i.next(  );
    String displayName = entity.getDisplayName(  );
    String homeInterface = entity.getHome(  );
    // etc.
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is Data Binding?
Before starting with the meat of the book, let me give you a basic introduction to data binding and the four concepts that make up a data binding package:
  • Source file/class generation
  • Unmarshalling
  • Marshalling
  • Binding schemas
I'll focus on each of these over the next several chapters, but I wanted to give you a bit of a preview here. You'll want to get an idea of the big picture so you can see how these components fit together.
I've already mentioned that the basic idea of data binding is to take an XML document and convert it to an instance of a Java object. Furthermore, that Java class is tailored to a business need and generally matches up with the element and attribute naming in the related XML document. Of course, I conveniently skipped over where that class comes from; this is where class generation comes in. In the most common XML data binding scenario, this class is not hand coded (that's quite a pain, right?). Instead, a data binding tool that will generate this source file (or source files) for you is provided.
In a nutshell, data binding packages allow you to take a set of XML constraints (DTD, XML Schema, etc.) and create a set of Java source files from these constraints. I'll dive deeper into the specifics of this subject in Chapter 3. In general, it works like this: an element is defined in a DTD called dealer-name, and a Java class called DealerName is generated. An XML Schema defines the servlet element as having an attribute called id and a child element named description, and the resultant Java class (Servlet) has a getId() method as well as a getDescription() method. You get the idea—a mapping is made between the structure laid out by the XML constraint document and a set of Java classes. You can then compile these classes and begin converting between XML and Java.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What You'll Need
Finally, I want to let you know what packages, projects, and tools you'll need to work through this book. I'll address the installation and setup details of each in the chapters in which they are used, but you may want to go ahead and download these items before getting started (especially if you're on a slow Internet connection. That way, you're not stuck waiting on a download when you'd rather start a new chapter and example set.
First, you'll need Sun's JAXB. While JAXB is the least mature of the available data binding frameworks, Sun has often leveraged its Java influence to turn out what becomes the standard against which other packages are measured. Because of that, I'll spend the first half of this book discussing the various data binding components in light of their relation to JAXB. You can download the early-access version of JAXB at http://java.sun.com/xml/jaxb/index.html. The specification, as of this writing, is currently released as Version 0.21, and the implementation is a 1.0 release. I'll cover setting up JAXB for use with the examples in the next chapter.
Additionally, I'll cover three other data binding implementations, all open source projects. I do this for obvious reasons: I'm an open source advocate, it's easy for you to get, and as I've run into occasional bugs in writing this book, I've been able to fix them and save you some headaches. There are several commercial data binding applications, but I've yet to see anything that merits the high price tags they command (you will typically pay a low per-developer price, as well as a much higher one-time deployment fee). The open source packages have matured and serve me well in numerous production applications. You're welcome to use commercial packages, although the examples will have to be tweaked to work within those frameworks.
The first data binding implementation I'll cover is Enhydra Zeus in Chapter 7. I'm partial to this implementation, since I founded the project, but I will cover it and the other implementations as they relate to Sun's JAXB. You can download Zeus from
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Theory and Concepts
In this chapter, I need to spend a little more time on some basic theory. I know you're ready to get to some code, but reading through this section will prepare you for the terms and concepts that I'll use later in the book and will also allow you to focus on application throughout the rest of the chapters. In the last chapter, you got a very quick rundown of both data-centric and business-centric APIs. In this chapter, I drill down into some of these APIs. However, instead of detailing what the APIs are, or how to use them, I focus on their relation to data binding. For example, most data binding packages allow you to set a SAX entity resolver, so I spend a little time detailing what that is. Since you won't ever need to use a SAX lexical handler, though, I skip right over that. Make sense?
In this chapter, I also explain how XML is modeled with constraints, cover the various constraint models currently available, and then funnel this into discussion of how constraints are critical to any data binding package. This will set the stage for Chapter 3, for which you need to have a good understanding of XML validation, DTDs, and XML Schema. Additionally, you'll learn about some of the newer constraint models that may affect data binding, like Relax NG.
Finally, I get a bit conceptual (but only briefly) and talk about the relevant factors for a good data binding API. You'll learn about runtime versus compile-time considerations, how versioning is a tricky issue in data binding, and what it takes to interoperate between data binding implementations. In addition to preparing you for a better understanding of the rest of the book, this section will be critical for those of you still deciding on a data binding implementation. Once you make it through this section, though, it's code the rest of the way through—I promise!
As I mentioned in the introductory chapter, data-centric XML APIs provide the lowest levels of interaction available to Java developers. Because of this, they form the backbone of many higher-level APIs, like data binding. Understanding them is important to effectively use a data binding tool. Not only does a keen understanding of these APIs help interpret error conditions and enhance performance, but it often allows you to set options on the unmarshalling and marshalling process that can drastically change the underlying parser's behavior. In this section, I cover the APIs that are fundamental to data binding and the concepts within these APIs that are critical to using a data binding framework.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Foundational APIs
As I mentioned in the introductory chapter, data-centric XML APIs provide the lowest levels of interaction available to Java developers. Because of this, they form the backbone of many higher-level APIs, like data binding. Understanding them is important to effectively use a data binding tool. Not only does a keen understanding of these APIs help interpret error conditions and enhance performance, but it often allows you to set options on the unmarshalling and marshalling process that can drastically change the underlying parser's behavior. In this section, I cover the APIs that are fundamental to data binding and the concepts within these APIs that are critical to using a data binding framework.
SAX, the "old faithful" of Java and XML APIs, is critical to any good data binding package. It is most often used as the API that actually handles the process of unmarshalling an XML document into a Java object. Because SAX is a very fast, read-only API, it is perfect for providing a high-performance means of reading in XML data and setting member variables on generated Java classes. SAX is also lightweight in terms of packaging (while some parsers like Apache Xerces are large, the binary distribution of Crimson and other SAX-compliant parsers can manage to stay in the 200-400 KB range), which is great for running data binding in limited-memory environments (think mobile and embedded devices).
Because of this, you will often need to interact with SAX objects and methods, even at the data binding level. For example, SAX provides a means of setting an error handler, defined through the org.xml.sax.ErrorHandler interface. This allows parsing warnings and errors to be dealt with gracefully, rather than bringing a system to a grinding halt. Most data binding projects allow you to set an ErrorHandler implementation on a class to be unmarshalled (prior to the unmarshalling, of course) so you can customize error handling. In the Lutris Enhydra project, for example, the error handler implementation shown in Example 2-1 demonstrates how errors can be logged before being reported back to the application.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Dependent APIs
When it comes to business-centric APIs, the tables turn a bit. Instead of a data binding package relying on these APIs, higher-level APIs often rely on data binding. This makes sense, as all programming is simply a layering of code that moves from the very specific (shifting bits) to the very general (buying a DVD). I won't spend too much time in this section, as these APIs can change their use of data binding as quickly as I can write about them. I'll touch on only a few items and then move on to XML constraints
SOAP is a perfect example of an API that can use data binding very naturally. Consider that the entire purpose of SOAP is to transfer information between systems. This data can be very complex though, and even user-defined.
For example, here's a fairly basic SOAP response:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
           SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  <SOAP-ENV:Body>
    <resp:stockQuoteResponse xmlns:resp="http://www.stockQuotes.com">
      <quote symbol="ALGX" name="Allegiance Telecom">
        <volume>2,964,600</volume>
        <averageVolume>924,318</averageVolume>
        <marketCap>411,700,000</marketCap>
      </quote>
    </resp:stockQuoteResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Don't get hung up in the envelope and header information; it's the body of the message that is interesting in relation to data binding. Because data has to be transferred via XML, data binding can offer a means of converting that data into XML. You can see that, in this case, the data is a stock quote.
Currently, most SOAP packages pick this data apart piece by piece and convert each to XML. However, consider that this same data could be represented just as well by a Java class like this:
public class Quote {
    private String symbol;
    private String name;
    private float volume;
    private float averageVolume;
    private long marketCap;
  
    public String getSymbol(  );
    public String getName(  );
    public float getVolume(  );
    public float getAverageVolume(  );
    public long getMarketCap(  );
  
    // Other mutator methods
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Constraint-Modeled Data
Once you've got a handle on the APIs involved with data binding (and those that could depend on it), you need to have a solid understanding of XML constraints. These constraints are one of the most important aspects of working with class generation (along with the binding schema), and your constraint model will dictate the classes that result. Good constraint modeling will result in efficient, business-oriented classes; however, poor modeling can result in hundreds of classes or convoluted names and methods.
One thing I do want to mention before diving into this section and the rest of the book is that I expect you to know the basics of DTDs and XML Schema. When I cover alternatives like Relax NG, I'll include some basic explanations related to the examples, but I don't want to spend time covering syntax of DTDs and schemas. There are plenty of available books on the subject, so you may want to have one or more of these handy as you work through the examples. I'm also going to assume that you can pick up some skills by following along with the examples; in other words, I'm not going to spend a lot of time talking about constraint basics, except those that relate specifically to data binding. Hopefully seeing lots of DTDs and schemas in this book will make you examine how you write your own constraints and pick up some good ideas. That said, let me dive into specific constraint models and what to watch for when writing constraints for use in data binding class generation.
Currently, DTDs are the basis of most data binding packages. DTDs were defined in the XML 1.0 specification, and you can learn about their syntax and limitations in O'Reilly's Learning XML or XML in a Nutshell. DTDs are not as expressive as many other constraint models, like XML Schema or Relax NG, but they remain the core of XML constraints. Tens of thousands, if not hundreds of thousands, of DTDs are used in production today. Because of this, even if you don't ever plan to write a DTD, you'll need to understand them and how to structure them for efficient data binding use.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
API Transparence
Before wrapping up on theory and concepts, I wanted to dive into some theoretical issues; don't worry, I'll keep it short and to the point! The issues I want to address relate to API transparence. When using data binding, you actually spend very little time working directly with the data binding API itself; instead, you work with classes generated by the API. Because of that, these generated classes become critical to your applications. However, when an API severs itself from the classes it generates, you can run into all sorts of nasty problems.
Actually, the API only appears to sever itself in many cases. In other words, many frameworks generate classes with methods like this:
public static EjbJar unmarshal(InputStream inputStream) 
    throws IOException {
    return (EjbJar)Unmarshaller
        .unmarshal(inputStream, EjbJar.class);
}
As you can see, the method on the generated class simply hides the details of using the API from your programs. However, from your application's point of view, you aren't interfacing with the data binding API in your code.
The first thing you'll want to make note of is the level of independence your generated classes offer you. In other words, are you tethered to the data binding API at runtime once classes are generated? Or do your classes run without ever using that API? The latter case is referred to as API independence. Obviously, the fewer dependencies your generated classes have, the easier deployment becomes.
Another question to ask is that of version independence: do your classes have to use a specific version of SAX, a vendor's parser, or your data binding framework? These are all critical questions and can cause bugs that are extremely tricky to track down. Like packaging up your data binding framework (if your generated classes require them), you'll need to supply appropriate versions of SAX, parsers, and other APIs, if your framework requires them at runtime. By knowing the answers to these questions, you'll not only be prepared to use a data binding framework, but also to deploy the solutions it creates. In fact, each issue deserves a detailed look, given here.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Generating Classes
Now that we're through the formalities, I want to focus specifically on the JAXB data binding framework. In this chapter, I start by discussing how to take a set of XML constraints and convert those constraints to a set of Java source files. In addition to seeing how this work with JAXB, this chapter should give you a solid idea of how class generation works so that when we move to other frameworks (in the second half of this book), you'll already have a handle on class generation and how it works. I also briefly touch on the future of JAXB—specifically, which constraint models are supported and which should be supported in future versions.
Without belaboring the point, I want to be clear that this and other JAXB chapters were written using a prerelease version of Sun's JAXB framework (the 1.0 version was not yet available). Because of this, small inconsistencies may creep in as this book goes to press. If you run across a problem with the examples, consult the JAXB documentation and feel free to contact us. Details of who to send mail to are in the preface of the book, and you can also check the book's web site at http://www.newInstance.com.
First, let's run through the process flow involved with generating constraints. This will help you get an idea of where we're going and how the pieces in this chapter fit together. It should also form a simple mental checklist for you to follow when generating classes; if you skip a step, problems crop up, so be sure to take each in turn. Here's how the steps break down:
  1. Create a set of constraints for your XML data.
  2. Create a binding schema for converting the constraints into Java.
  3. Generate the classes using the binding framework.
  4. Compile the classes and ensure they are ready for use.
I'll cover each step in order.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Process Flow
First, let's run through the process flow involved with generating constraints. This will help you get an idea of where we're going and how the pieces in this chapter fit together. It should also form a simple mental checklist for you to follow when generating classes; if you skip a step, problems crop up, so be sure to take each in turn. Here's how the steps break down:
  1. Create a set of constraints for your XML data.
  2. Create a binding schema for converting the constraints into Java.
  3. Generate the classes using the binding framework.
  4. Compile the classes and ensure they are ready for use.
I'll cover each step in order.
The first step is to create a set of constraints for your XML data. If you followed my advice from Chapter 2, then you are doing this before writing your XML documents. That tends, as I mentioned, to produce more organized constraint models. You'll want to ensure that your constraint model is complete, as well; the last thing you want is to have to add an attribute or element that you forgot and then regenerate your source files. As mentioned previously, this can cause conflicts with older versions of generated classes conflicting with your updated ones.
Additionally, now you need to ensure that your constraint model syntax is supported by the binding framework you want to use. In other words, if you go to a lot of trouble to generate a documented XML Schema and then find out that your framework of choice supports only DTDs, expect some yelling and screaming. Take the time before writing constraints to verify this, or you can't say that I didn't warn you when things get ugly. As a general rule, you will never go wrong using DTDs right now, as all frameworks support them. I'd guess that a year or two from now, XML Schemas will be just as safe, but the frameworks simply aren't there yet.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating the Constraints
The first step in getting ready for class generation, as you can see from Figure 3-1, is getting a set of constraints ready to generate classes from. As this isn't a book on writing XML (and there are plenty of good ones on the subject already), I'm not going to spend time describing how to formulate constraints.
I'll assume that you're capable of figuring out how you want your data represented and then using DTDs or schemas or your constraint model of choice to describe that data. I do want to touch on a few points relevant to data binding, and JAXB specifically, though, and then provide several DTDs for working through the examples.
First, as I've mentioned several times, JAXB currently supports only DTDs. From what I can gather from the specification, newsgroups, and mailing lists, this is the plan all the way through the 1.0 final version of the specification and framework. There is a lot of momentum to follow up this release with a "version.next" that does support XML Schema, though. JAXB does support all the features of DTDs, so you should be able to use any DTDs you've already developed for your data binding needs.
To get started, I want to present a simple DTD that I'll use as a starting point for most of the rest of this chapter. Example 3-1 shows that DTD, which represents a simple movie database.
Example 3-1. Movie database DTD
<!ELEMENT movies (movie+)>
<!ATTLIST movies
          version    CDATA    #REQUIRED
>

<!ELEMENT movie (title, cast, director?, producer*)>

<!ELEMENT cast (actor+)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT director (#PCDATA)>
<!ELEMENT producer (#PCDATA)>

<!ELEMENT actor (#PCDATA)>
<!ATTLIST actor
                 headliner    (true | false)    'false'
>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Binding Schema Basics
Once you've got your constraints (I saved my movie database DTD as movies.dtd), you're ready to create a binding schema for your classes. This will instruct the class generation tool to generate classes, to use a specific Java package, to use collections, and a variety of other options. Although I won't spend a lot of time on the schemas in this chapter, I'll give you some basics that will get us through some simple examples. Specifically, I'll deal with global options here and leave the local options, as well as more advanced features, to Chapter 6.
The first thing that you'll want to get a handle on is the "minimum binding schema." This is the least-amount-of-work principle; often, you'll want to generate classes from your DTD without any changes. To do this, you'll need to create a binding schema that provides very minimal information to the JAXB schema compiler tool.
The JAXB binding schema is an XML document, and the root element must be xml-java-binding-schema. It must also have a single attribute, version, and currently the only allowed value for this attribute is 1.0-ea.
The JAXB download comes with the DTD for this schema. It's located in the [jaxb-root]/doc/ directory and called xjs.dtd.
For a minimal binding schema, you must specify the root element of the DTD being passed in; this allows JAXB to determine which generated object (in source code) is the "top-level" one. This is accomplished through the element element (yup, you read that right). By supplying the root attribute and giving it a value of true, you've given JAXB what it needs. Add to this the name attribute, which identifies the element you're working on and, finally, the type attribute, which tells JAXB what type of Java construct to create from the element. For the movies element, you want a Java class, so use the class value for this attribute.
That idea took a paragraph to explain, but requires only three or four lines to put into action. Example 3-3 shows a binding schema for the movie database DTD.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Generating Java Source Files
At this point, you've got all of the required components to generate source code from the movie database constraint set. In this section, I detail the actual process of using the command-line tools in JAXB to generate classes. You'll find out how to get set up with the JAXB framework, use the provided scripts, and actually generate classes.
The first thing you need to do, if you haven't already, is download the JAXB release. Visit http://java.sun.com/xml/jaxb and follow the links to download the reference implementation of JAXB. I also recommend that you download the PDF specification for reference. Once you've got the release (named something like jaxb-1_0-bin.zip), you'll want to extract this to a directory on your hard drive. On my Windows machine, I used c:\dev\javajaxb\jaxb-1.0, and it's extracted at /dev/javajaxb/jaxb-1.0 on my Mac (running OS X).
You'll want to note the two jar files in the lib/ directory, jaxb-rt-1.0-ea.jar and jaxb-xjc-1.0-ea.jar. The first is used for JAXB classes at runtime (indicated by the rt), and the second contains the classes used in schema compilation. In other words, you'll want the first in your classpath for your applications using generated classes and the second in your classpath when generating those classes.
Additionally, JAXB comes with a script in the bin/ directory, used for invoking the Java class that starts the schema compiler for class generation. However, at least in the version I've got, this script works only on Unix-based systems. Instructions for invoking the JAXB schema compiler on Windows are available, but they are pretty poor. To help Windows users, Example 3-5 shows a batch file that invokes the schema compiler (and report errors usefully) for Windows systems. I've saved it as xjc.bat, also in my bin/ directory.
Example 3-5. Batch file for class generation using JAXB
@echo off
  
if "%JAVA_HOME%" == "" goto java_home_error
if "%JAXB_HOME%" == "" goto jaxb_home_error
  
set LOCALCLASSPATH=%JAVA_HOME%\lib\tools.jar;%JAXB_HOME%\lib\jaxb-xjc-1.0-ea.jar
  
echo Starting JAXB Schema Compiler...
  
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Unmarshalling
In this chapter, we move from creating Java source files to creating Java objects. In Chapter 3, you built a framework of objects (compiled source files) that represented your constraints. However, this framework isn't particularly useful on its own. Just as a DTD isn't of much use without XML, generated classes aren't any good without instance data. We take the next logical step in this chapter and work on taking an XML document and generating instance data.
I start out by walking you through the process flow for unmarshalling, which is the technical term for converting an XML document into Java object instances. This will give you the same background as the class generation process flow section did and prepare you to work through the rest of the chapter. From there on, it's all working code. First, I discuss creating instance documents, XML documents that conform to your constraint set. Once you've got your data represented in that format, you're ready to convert the XML into Java; the result is instances of the classes you generated in the last chapter. Finally, I cover how to take this data, in Java format, and use it within your application. You'll want to have your XML editor and Java IDE fired up because there is a lot of code in this chapter; let's get to it.
As in the case of class generation, I want to spend a little time walking through the process flow of unmarshalling XML data into Java objects. This is useful in understanding exactly what happens when you invoke that unmarshal( ) method (or whatever it's called with your framework). Rather than relying on a black box process, you'll be able to know exactly what goes on, troubleshoot oddities in your applications, and maybe even help out the framework programmers with a bug here and there.
  1. Construct XML data to unmarshal into Java objects.
  2. Convert the XML data into instances of generated Java objects.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Process Flow
As in the case of class generation, I want to spend a little time walking through the process flow of unmarshalling XML data into Java objects. This is useful in understanding exactly what happens when you invoke that unmarshal( ) method (or whatever it's called with your framework). Rather than relying on a black box process, you'll be able to know exactly what goes on, troubleshoot oddities in your applications, and maybe even help out the framework programmers with a bug here and there.
  1. Construct XML data to unmarshal into Java objects.
  2. Convert the XML data into instances of generated Java objects.
  3. Use the resultant Java object instances.
Each step is detailed here.
First, you need to have some XML data to start with. This probably isn't any great revelation to you, but it's worth taking a look at. You'll need an XML document that matches up with the constraints designed in the class generation process. Additionally, this document must be valid with respect to those constraints. Valid means that the structure and data in the document fulfill the data contract set out by your DTD. I talk in detail about how to validate your documents both before and during data binding later on in this chapter.
There's not a lot of complexity in this step, so I won't dwell on it. There are certainly some subtle issues to work through in ensuring that the data in your XML document correctly maps to where it belongs in your Java classes, and I cover that in the more detailed sections of the chapter. For now, though, as long as you've got an XML document and have a set of generated classes from the document's DTD, you're ready to roll.
The guts of the unmarshalling process is the conversion from XML to Java. This is where the most interesting action takes place in any framework. However, it's also the place where the process itself varies the most between frameworks. While the starting point (an XML document) and ending point (Java object instances) are the same, the "in-between" is not. Still, basic principles that are important to understand are at work, and these basics apply to all frameworks.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating the XML
The first step is to create XML data to be unmarshalled into Java. You'll find that you spend as much time creating XML documents as you do in any other aspect of data binding, as it provides the data for your application. Additionally, it's often easier to open up an editor like notepad or vi than it is to code a program to populate Java objects and then marshal them (although I'll talk about that approach in the next chapter, which focuses on marshalling Java to XML). So let's talk XML.
I've spent a lot of time talking about constraint models, setting up your data structure, and other conceptual type ideas. In this section, you get to move a little closer to the practical. Once you've got your constraint model set up (as shown in Chapter 3), you need to model your actual data. In this case, the modeling part of that task is done, and all that is left is filling a document with data. With the emerging XML editor scene, this becomes a piece of cake. For example, Figure 4-3 shows a screenshot of XML Spy, which allows a simple filling of constraints with data; as you can see, this is a trivial task.
Figure 4-3: Editing XML with XML Spy
Many of you will use simpler editors, but the principle is the same: take a DTD, figure out what data goes in the elements and attributes as defined by that DTD, and create an XML document.
One issue that comes up often is the handling of whitespace. Will the level of indention you use change the data-bound data? What about using tabs versus spaces or single versus double quotes? These issues are important in low-level APIs like SAX because those APIs are intended to give you direct control over the data. However, in higher-level APIs like data binding, these choices become pretty inconsequential. For example, the whitespace between the root and child elements in this document fragment is completely irrelevant when using data binding:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting to Java
Now comes the fun part: turning these XML documents into Java object instances. I'm going to really take this process step by step, even though the steps are awfully simple. The point of this exercise isn't to bore you or fill pages; you need to be able to understand exactly what happens so you can track down problems. As a general rule, the higher level the API, the more that happens without your direct intervention. That means that more can go wrong without the casual user being able to do a thing about it. Since you're not a casual user (at least not after working through this book), you'll want to be able to dig in and figure out what's going on.
The first step in unmarshalling is getting access to your XML input. I've already spent a bit of time detailing the process of creating that XML; now you need to get a handle to it through a Java input method. The easiest way to do this is to wrap the XML data in either an InputStream or a Reader, both from the java.io package. When using JAXB, you'll need to limit your input format to InputStreams, as Readers aren't supported (although many other frameworks do support Readers, it is simple enough to convert between the two input formats).
If you know much about Java, there isn't any special method you need to invoke to open a stream; however, you do need to understand what state the stream is in when returned to you after unmarshalling completes. Specifically, you should be aware of whether the stream you supplied to the unmarshalling process is open or closed when returned from the unmarshal( ) method. The answer with respect to the JAXB framework is that the stream is closed. That effectively ends the use of the stream once unmarshalling occurs. Trying to use the stream after unmarshalling results in an exception like this:
java.io.IOException: Stream closed
        at java.io.BufferedInputStream.ensureOpen(BufferedInputStream.java:123)
        at java.io.BufferedInputStream.reset(BufferedInputStream.java:371)
        at javajaxb.RereadStreamTest.main(RereadStreamTest.java:84)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using the Results
So far, the discussions have been technical, but I really haven't shown you how to put it all together. In this section, I will try to show you a couple of interesting uses of data binding and how they can serve as models for your own applications that could benefit from data binding. Hopefully this will finally satisfy your desire to see data binding in practical action.
The most common use of data binding is to turn XML directly into business objects. These objects are given contextual meaning, as in the case of the movie database. The application uses this data as a set of movies, and that use applies meaning to the data. This is quite different from the normal use case for XML (without data binding); in those cases, data has to be extracted and then placed into existing business objects. With data binding, that process is turned into a simple step (the unmarshal( ) method invocation).
As a practical example of this, Example 4-3 introduces the MovieServlet class. This class provides web access, through a GET request, to the data in the current movie database. I won't spend time covering the semantics of servlet code; if you aren't comfortable with servlets, check out Jason Hunter's Java Servlet Programming (O'Reilly). In any case, look at the example code, and I'll discuss how the data-bound classes are used.
Example 4-3. The MoviesServlet class
package javajaxb;
  
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
  
// Servlet imports
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
  
// Movie database generated classes
import javajaxb.generated.movies.*;
  
public class MoviesServlet extends HttpServlet {
  
    /** The Movies database object */
    private Movies movies = null;
  
    /** Any error that occurred. */
    private String errorMessage = null;
  
    /** The XML document storing the movie database */
    private static final String MOVIES_XML_DOCUMENT =
        "/dev/javajaxb/ch04/src/xml/movies.xml";
  
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
  
        // Load the database using JAXB
        try {
            // Load the XML
            File xmlFile = new File(MOVIES_XML_DOCUMENT);
            FileInputStream inputStream = new FileInputStream(xmlFile);
  
            // Unmarshal
            movies = Movies.unmarshal(inputStream);
        } catch (Exception e) {
            errorMessage = e.getMessage(  );
        }
    }
  
    public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {
  
        // Handle any error conditions that might have occurred.
        if (movies == null) {
            error(res);
        }
  
        // Get output stream
        PrintWriter out = res.getWriter(  );
        res.setContentType("text/html");
  
        // Write out movie database
        out.println("<HTML><HEAD><TITLE>Movie Database</TITLE></HEAD>");
        out.println("<BODY>");
        out.println("<H2 ALIGN='center'>Movie Database</H2>");
 
        List movieList = movies.getMovie(  );
        for (Iterator i = movieList.iterator(); i.hasNext(  ); ) {
            Movie movie = (Movie)i.next(  );
  
            // Title
            out.print("<B><FONT SIZE='+1'>");
            out.print(movie.getTitle(  ));
            out.println("</FONT></B><BR />");
  
            // Director
            String director = movie.getDirector(  );
            if (director != null) {
                out.print("Director: ");
                out.print(director);
                out.println("<BR />");
            }
  
            // Producer
            out.println("Producers:<BR /><UL>");
            List producerList = movie.getProducer(  );
            for (Iterator j = producerList.iterator(); j.hasNext(  ); ) {
                out.print("<LI>");
                out.print((String)j.next(  ));
                out.println("</LI>");
            }
            out.println("</UL>");
  
            // Cast
            out.println("Starring:<BR /><UL>");
            Cast cast = movie.getCast(  );
            List actorList = cast.getActor(  );
            for (Iterator j = actorList.iterator(); j.hasNext(  ); ) {
                Actor actor = (Actor)j.next(  );
                out.print("<LI>");
                out.print(actor.getContent(  ));
                if (actor.getHeadliner(  ).equalsIgnoreCase("true")) {
                    out.print(" (Headliner)");
                }
                out.println("</LI>");
            }
            out.println("</UL>");
  
            out.println("<HR WIDTH='80%' />");
        }
  
        out.println("</BODY></HTML>");
        
        out.close(  );
    }
  
    private void error(HttpServletResponse res) throws IOException {
        PrintWriter out = res.getWriter(  );
        res.setContentType("text/plain");
  
        out.write(" ************* ERROR OCCURRED ***************\n\n");
        out.write("Error: " + errorMessage + "\n");
        out.close(  );
    }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: Marshalling
Now that you have made it this far, you should start to feel pretty confident. Class generation got you started, and now you have cruised through unmarshalling. Marshalling is almost an exact mirror image of the unmarshalling process, so it should be a real snap at this point. I begin, as has been my custom, by taking the marshalling process flow step by step at a high level. This will give you the perspective needed for the detailed sections in the rest of the chapter.
Once you've got a handle on the basic flow, you'll learn how to take your Java objects and validate the data in them. This ensures that the XML resulting from your Java objects is still legal data for the original data constraints. Then you'll move on to the actual conversion from Java to XML and look at the resultant XML created from this process. Finally, I touch on creating process loops, where data is converted from XML to Java, back to XML, and then back to Java.
By now, you should know the drill here. As in unmarshalling, there are three basic steps in converting a Java object (or set of objects) to XML. They are listed here and then detailed in the following sections:
  1. Validate Java objects to ensure data validity.
  2. Convert Java data objects into XML documents.
  3. Use/store the resultant XML documents.
The first step, validation of Java objects, assumes that you already have Java objects available for conversion to XML. Along with this assumption is another detail that I will discuss in more detail later in this chapter. That detail is whether your Java objects were originally unmarshalled from XML documents.
When using the JAXB framework, only objects that were originally generated by that framework are candidates for marshalling back into XML. This means that your own application objects, even if they are in the JavaBean's format (with accessors and mutators for member variables), are not eligible for conversion to XML. While this might not seem an imposition right now, data binding offers an attractive solution for persisting Java objects to XML. Using XML for persistence doesn't work out with your existing objects (at least when using the current version of JAXB). As a result, you need to make sure you apply the steps in this chapter only to objects originally created using JAXB.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Process Flow
By now, you should know the drill here. As in unmarshalling, there are three basic steps in converting a Java object (or set of objects) to XML. They are listed here and then detailed in the following sections:
  1. Validate Java objects to ensure data validity.
  2. Convert Java data objects into XML documents.
  3. Use/store the resultant XML documents.
The first step, validation of Java objects, assumes that you already have Java objects available for conversion to XML. Along with this assumption is another detail that I will discuss in more detail later in this chapter. That detail is whether your Java objects were originally unmarshalled from XML documents.
When using the JAXB framework, only objects that were originally generated by that framework are candidates for marshalling back into XML. This means that your own application objects, even if they are in the JavaBean's format (with accessors and mutators for member variables), are not eligible for conversion to XML. While this might not seem an imposition right now, data binding offers an attractive solution for persisting Java objects to XML. Using XML for persistence doesn't work out with your existing objects (at least when using the current version of JAXB). As a result, you need to make sure you apply the steps in this chapter only to objects originally created using JAXB.
Once your objects are candidates for marshalling, you need to validate the data in these objects. This ensures that the original constraint set used in your XML documents (the DTD, schema, or other format used to generate Java classes) is valid for any new data set on your objects. If an enumeration, for example, is specified and only the values thriller, comedy, and drama are allowed for the genre element, you would not be able to marshal a Java object whose genre member variable was set to the value
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Validating Java Objects
The first step in getting ready to convert your Java data into its XML equivalent is to ensure that the data in the object instances is appropriate for conversion. You will need to use JAXB's validation, as well as some code of your own, to ensure that errors are handled before marshalling occurs. This allows better error handling and also allows you to react, as a programmer, to user error.
The first thing you need to understand about the validation that occurs during JAXB marshalling is that it is by no means perfect. In other words, the validation will catch some problems, but not others. If you don't have a thorough understanding of which errors will be caught and which will not, you will quickly end up with invalid XML from a marshalling process. This invalid XML is often not discovered until much later when that XML is used in some other part of your application.
As a general rule, JAXB will catch only the problems related to missing attributes and elements. The easiest way to see this is through the use of a simple example program. Example 5-1 shows the creation of a new movies database and then the marshalling of that database to XML.
Example 5-1. Errors from missing attributes
package javajaxb;
  
import java.io.File;
import java.io.FileOutputStream;
  
// Generated Classes
import javajaxb.generated.movies.*;
  
public class ValidationTest {
  
    public static void main(String[] args) {
        try {
            // Create a movie database
            Movies movies = new Movies(  );
            // version attribute NOT set
  
            // Create a new movie
            Movie movie = new Movie(  );
            movie.setTitle("Attack of the Clones");
            movie.setDirector("George Lucas");
            movie.getProducer(  ).add("Rick McCallum");
            movies.getMovie(  ).add(movie);
  
            // Set cast
            Cast cast = new Cast(  );
            Actor obiwan = new Actor(  );
            obiwan.setContent("Ewan McGregor");
            obiwan.setHeadliner("true");
            cast.getActor(  ).add(obiwan);
  
            Actor anakin = new Actor(  );
            anakin.setContent("Hayden Christensen");
            anakin.setHeadliner("true");
            cast.getActor(  ).add(anakin);
            movie.setCast(cast);
  
            // Create output stream
            File file = new File("output.xml");
            FileOutputStream outputStream = new FileOutputStream(file);
  
            // Marshal back out
            movies.marshal(outputStream);
        } catch (Exception e) {
            e.printStackTrace(  );
        }
    }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting to XML
Once you're ready to actually perform the conversion to XML, invoking a marshal() method is about as simple as it gets. In this section, I'll continue to use the MoviesServlet introduced in Chapter 4 and demonstrate how changes can be made and marshalled back out to XML. This will give you a clear idea of how marshalling works in a realistic way.
All that you need for Java input is a set of object instances from JAXB-generated classes. The movie database classes fit the bill, and the instances unmarshalled from the last chapter are perfect candidates. Before bothering to convert these back to XML, though, it makes sense to allow the user to change the values (otherwise, what is the point of marshalling?).

Section 5.3.1.1: The server

To accommodate modification of the movie database, it is possible to add some new actions to the servlet to complement the "list" action already handled. First, add a few import statements to the class:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
  
// Servlet imports
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
  
// JAXB imports