Skip to main content

Data binding with Castor, Part 3: Map between schemas

Use Castor mapping files

Brett D. McLaughlin, Sr. (brett@newInstance.com), Author and Editor, O'Reilly Media, Inc.
Photo of Brett McLaughlin
Brett McLaughlin is a bestselling and award-winning non-fiction author. His books on computer programming, home theater, and analysis and design have sold in excess of 100,000 copies. He has been writing, editing, and producing technical books for nearly a decade, and is as comfortable in front of a word processor as he is behind a guitar, chasing his two sons around the house, or laughing at reruns of Arrested Development with his wife. His last book, Head First Object Oriented Analysis and Design, won the 2007 Jolt Technical Book award. His classic Java and XML remains one of the definitive works on using XML technologies in the Java language.

Summary:  After reading Parts 1 and 2 in this series, you should be comfortable using Castor to convert from XML to Java™, and then back again. In this article, you'll learn to add flexibility to your functionality, through Castor mapping files. You'll no longer be constrained by the names of elements in your XML document, or by the member variable names in your Java classes.

View more content in this series

Date:  29 Jan 2008
Level:  Advanced
Activity:  4496 views

What you should already have (redux)

As in the last article, this article makes some assumptions about what you've got setup on your system, and what you know how to do. First, as described in Part 1 of this series, you need to have the latest version of Castor downloaded, installed, and setup for use with your classpath and related Java libraries (check out the first article in this series, linked to in Resources). Then, as detailed in Part 2, you should be comfortable with Castor's basic marshalling and unmarshalling facilities.

So you should be able to take an XML document, use Castor to extract the data in that document, and work with it using your own Java classes. In data binding terminology, that's called unmarshalling. The same is true in reverse, or marshalling: you should be able to take your Java classes and convert the data stored in those classes' member variables into an XML document. If you're not comfortable using the Castor unmarshaller and marshaller programmatically, you should review Part 2 (again, that's linked to in Resources).


Data binding in an imperfect world

At a glance, it would seem like you should know what you need to work with and use Castor effectively: setup, marshalling, and unmarshalling. But, everything you've learned so far only works in the so-called perfect world. That's a world where everyone writes great XML with useful element names like "title" and "authorAddress," instead of "t" or "aa." Your Java classes are created in an organized manner, with a singular as the class name (like "Book") and singular nouns for the member variables, like "isbn" and "price." And data types are correct, too: no developers made price an int instead of a float or used an array of chars for string data because they still think they're writing C code.

But that perfect world isn't one that most programmers get to live in (I'm still looking for a magical wardrobe to take me to that world). In the world where most programmers get paid twice a month, and have to pay a mortgage with that paycheck, XML documents often have awful element and attribute names, not to mention loads of namespace issues to deal with. Element data is stored in attributes, and some data is even delimited with pipe symbols or semicolons.

Java classes are inherited, and the cost in time and effort to retool them is greater than any clear benefit. Those classes don't often map cleanly to an XML schema (the idea that the XML and data wranglers and the Java guys would hang out is also pretty magical), and when they do in some cases, they certainly don't across all classes and data. Just as XML element names are bad, so are many Java variable names. Ever run across classes coded by someone using Hungarian notation, where all member variables start with "m," like mTitle? It's not a pretty sight.

In these cases, the approach to data binding that you've picked up so far won't get you very far. At best, it will get you messy XML documents with Hungarian element names, or kludgy Java classes with a structure that doesn't make much sense. That's not acceptable. What good is Castor—or any data binding framework—if you can't take an XML document's data and manipulate it the way you want?


The goals of flexible data binding

To start, note that using mapping files—with Castor or any other data binding framework—takes some time. You'll have to learn some new syntax, first of all. Even if the mapping file uses XML as the format—and most frameworks do just that—you'll have new elements and attributes to figure out. You'll also have to do more testing, ensuring that mapping from XML to Java code, or Java code to XML, produces the results you want and expect. And finally, you'll encounter a lot more errors in data binding, as you specify the mapping yourself rather than let your framework handle it. That means if you indicate your framework should map from the fiddler element in XML to the violin attribute in Java code, but you accidentally tell the framework the attribute is on the player class—and not the Player class—you'll get an error. Suddenly, spelling, capitalization, underscores, and single- and double-apostrophes become very important.

Before you dig into all of these nuances, you should have a good reason for doing so. Learning mapping files just so you can say you know them is a waste of time. However, mapping has some real benefits.

Your Java code isn't constrained by your XML naming

I've already talked a bit about how capitalization can be a source of pain when you move from XML to Java code. The most common approach to XML is to use all lowercase names with dashes, like first-name. Sometimes, you'll even see first_name. Both of these turn into fairly ugly Java attribute names; nobody wants to call getFirst-name() in their code. In fact, most of the documents that do use camel-case naming, like firstName, are authored by programmers, rather than XML-centric developers or data managers. With mapping files, it's trivial to map from an XML-centric name, like first-name, to a Java-centric one, like firstName. And, best of all, you're not trying to get your XML guys to think like Java programmers, which is often a lot harder than learning some new mapping syntax.

Your XML isn't constrained by your Java naming

Yes, this seems rather obvious. If you can tweak your XML-to-Java naming, you can certainly do the same in reverse, and modify your Java names as the data those classes and attributes contain move into XML. But there's a more important, and often more subtle, benefit: You're also not bound by your Java class and package names.

This mostly becomes a matter of organization. Consider that for the most part, nesting elements in your XML are converted to class structure, with the most-nested elements becoming class properties (member variables). So take the XML shown in Listing 1:


Listing 1. XML representing a book
                
<?xml version="1.0" encoding="UTF-8"?>
<book>
 <authors total-sales="0">
  <last-name>Finder</last-name>
  <first-name>Joseph</first-name>
 </authors>
 <isbn>9780312347482</isbn>
 <title>Power Play</title>
</book>

Castor—or any other data binding framework—would probably assume you want a Book class, perhaps with a reference to several instances of an Author class. The author class should have a lastName and firstName member variable (note the naming issues already, but should the member variables in Author be last-name or lastName? The same goes for the first name). But what if that's not what you want? Suppose you store all authors, conference speakers, and professors in a single class, called Person, or Professional? You've got a real problem, and you shouldn't have to completely restructure and rename your XML elements to solve that problem. In fact, this is a case where mapping is the only way to keep your XML as is, without changing it because of choices that a Java programmer made.

Mapping lets you dictate naming on both sides of the Java-XML pipeline. Just as you don't want to change your Java code because of your XML document authors, you shouldn't have to change your XML structure to match an arbitrary organization of Java classes and member variables. And, while you're at it, insert Java packages into the mix. Although packages are less of an issue in Castor, you still have to store information about Java classes and packages in marshalled XML, which is a poor separation between your business logic (Java classes) and your data (XML). Mapping can solve all of these problems.

Mapping lets you add data binding to an existing environment

Both of the above issues—constraints levied on your XML or your Java code—are really about a larger issue. Most of the time, you have both a set of Java objects and an XML document or two. So you're not allowed the flexibility of the previous articles, where you could let Castor unmarshal your Java code to XML however it wanted, or generate or custom-build Java classes for your XML documents.

Instead, you're in the much more common position of adding a new technology—data binding—to an existing structure. In these cases, a mapping file can be the difference between using data binding and not. It allows you to have two fixed "endpoints"—your current object model and current XML structure—and still negotiate data between the two. In short, a good mapping system makes data binding useful in the real world, and not just a theoretical exercise.


A sample mapping scenario

First I'll put together a simple mapping scenario that you can use as an example. In the last article, you developed a Book and Author class. Those are shown below; Listing 2 is the Book class.


Listing 2. A Book class
                package ibm.xml.castor;

import java.util.LinkedList;
import java.util.List;

public class Book {

  /** The book's ISBN */
  private String isbn;
  /** The book's title */
  private String title;
  /** The authors' names */
  private List<Author> authors;

  public Book() { }

  public Book(String isbn, String title, List<Author> authors) {
    this.isbn = isbn;
    this.title = title;
    this.authors = authors;
  }

  public Book(String isbn, String title, Author author) {
    this.isbn = isbn;
    this.title = title;
    this.authors = new LinkedList<Author>();
    authors.add(author);
  }

  public void setIsbn(String isbn) {
    this.isbn = isbn;
  }

  public String getIsbn() {
    return isbn;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getTitle() {
    return title;
  }

  public void setAuthors(List<Author> authors) {
    this.authors = authors;
  }

  public List<Author> getAuthors() {
    return authors;
  }

  public void addAuthor(Author author) {
    authors.add(author);
  }
}

Listing 3 is the Author class.


Listing 3. An Author class
                package ibm.xml.castor;

public class Author {

  private String firstName, lastName;

  public Author() { }

  public Author(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public String getFirstName() {
    return firstName;
  }
  
  public String getLastName() {
    return lastName;
  }

}

Note: The only changes from the last article is the removal in the Author class of the total sales (totalSales) variable. On retrospect, it didn't make a lot of sense, so I removed it in this version of the class.

A more troublesome XML document

Instead of going with the XML from the last article, you'll use something that doesn't map quite so nicely. Listing 4 shows the XML document you want to bind to the Java classes in Listings 2 and 3.


Listing 4. XML for data binding
                
<?xml version="1.0" encoding="UTF-8"?>
<book>
 <author>
  <name first="Douglas" last="Preston" />
 </author>

 <author>
  <name first="Lincoln" last="Child" />
 </author>

 <book-info>
  <isbn>9780446618502</isbn>
  <title>The Book of the Dead</title>
 </book-info>
</book>

What needs to be mapped?

Your first task—before worrying about mapping file semantics or Castor's API, or anything else—is to figure out what you need to do to get the data from the XML from Listing 4 into the Java classes shown in Listings 2 and 3. Think about it a moment.

Here's the brief summary of how the XML should map to the Java classes:

  • The book element should map to an instance of the Book class.
  • Each author element should map to an instance of the Author class.
  • Each Author instance should be added into the authors list in the Book instance.
  • For each Author instance, the firstName should be set to the value of the first attribute on the name element.
  • For each Author instance, the lastName should be set to the value of the last attribute on the name element.
  • The Book instance's ISBN should be set to the value of the isbn element, nested in the book-info element.
  • The Book instance's title should be set to the value of the title element, nested in the book-info element.

Some of these are things you already know how to do. For instance, mapping the book to an instance of the Book class is standard, and Castor will handle the task by default. But there are some new wrinkles, like in the case of the authors. While mapping an author element to an Author instance isn't too bad, there's not grouping element, like authors, that makes it clear that each author belongs to a single collection in a Book instance.

There are also some places where elements and attributes don't map directly to the Java object model. There's a variable for the first name and for the last name in the Author class, but only a single element— name —with two attributes for that data in the XML. And the title and ISBN of a book is nested in the book-info element, which doesn't map to any Java object.

Mapping is ideal for this situation. It will allow you to take this XML—which has the data you want, but not the structure—and still get the data within the document into your Java objects. And, as you'll soon see, the mapping file itself isn't hard to construct.


The Basic Mapping file

Mapping in Castor is achieved through the use of a mapping file, which is just an XML document that provides information about how to go from Java code to XML, and vice versa. And since you're already comfortable with XML, you'll find that authoring a mapping document is pretty easy. In fact, for simple mappings—where you're just changing names of an element to a Java class or member variable—the mapping file will take you seconds to put together.

This file is then used by Castor when you marshall and unmarshall, something you know how to do programmatically from the last couple of articles. You'll need just a single additional API call to Castor; everything else stays just the same.

The mapping element

Everything in Castor mapping files begins with a plain old XML document, and a mapping root element. You'll also want to reference the Castor mapping DTD. That way, you can validate your document, and make sure you don't have any problems with your structure and syntax. That makes things much easier if you have to debug your mapping.

Listing 5 shows the most basic mapping file.


Listing 5. Basic Castor mapping file
                
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">

<mapping>
  <!-- All your mappings go here -->
</mapping>

This obviously won't do anything, but it's the starting place that all your mapping files will use.

Mapping classes with the class element

Once you have your basic file, you almost always begin by mapping a Java class to an XML element. In this example, you need to map the Book class to the data in the book element. The mapping file looks at classes first, so you'll need to add a class element, and give the name of your fully-qualified Java class in the name attribute of the element, like this:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
  </class>
</mapping>

Now, you can indicate the XML element that class maps to, using the map-to element and the xml attribute. This element nests within the class element with the Java class (fully-qualified, including the package) that this XML maps to, like this:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
  <map-to xml="book" />
  </class>
</mapping>

This is pretty straightforward. In fact, the mapping file so far is only doing what Castor does by default. You might leave out this portion and let Castor handle the task, except for two reasons:

  1. You need to indicate how some of the specific fields in Book will be populated, such as the title and the ISBN.
  2. Once you use a mapping file, it's better to indicate how everything will be mapped. That provides self-documentation, and clarity in how your XML and Java code work together.

Mapping fields to elements

With a basic class-to-element mapping, you're ready to start mapping fields of the book class to specific elements within the XML document. Castor mapping files use the field element to indicate what Java member variable is being used, and the bind-xml element nested within that to indicate the XML to map to. So, here's how you map the title variable in the Book class to an XML element named title nested within the book element:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
    <map-to xml="book" />

    <field name="Title" type="java.lang.String">
                     <bind-xml name="title" node="element" />
                    </field>
  </class>
</mapping>

Property names insulate your code

The real value of using property names—which then translate into method names—is that the innards of your class are hidden. Whether you name your class member variable title or book-title or mTitle or _title, as long as you have a setTitle() method, Castor accepts the simple property name "title." This allows for lots of coding styles, and deals with a class based only on its public API: its getters and setters.

Noe a couple of things here. First, the name of the property is supplied (in this case, "title"). And this is the property name, not the member variable name. In other words, Castor will use your property name by calling set[PropertyName](). If you supply a property name of "foo", Castor will try to call setfoo() —and that's probably not what you want. So watch your capitalization carefully, and use the property name, not the variable name in the Java class.

The second thing to notice is the use of the type attribute. Here's where you tell Castor exactly what type to expect and to use for the data. In this case, it's simple; but in cases where you want a number stored as XML textual data stored as an integer, or a decimal, or even just as a string, it's critical that you indicate the correct data type. And you should use fully-qualified Java class names, as done here: java.lang.String.

In the bind-xml element, you give the name of the XML element to bind to—in this case, "title"—as well as whether you're binding to an element or attribute, through use of the node attribute. This lets you easily use both element and attribute data, which is just one more point of flexibility with mapping files.

Specifying the location of an XML element

But here's the first problem you need mapping to solve: the book's title and ISBN are nested within the book-info element, rather than directly inside the book element. So you'll do some work to make things behave the way they should.

When you run into a case like this—mapping a field in a class to data not directly within the corresponding XML element for that class—you need to use the location attribute, available on the bind-xml element. The value for this attribute should be the element in the XML document that contains the data you want to bind to. If you bind to element data, it should be the parent element of the target element; if you bind to attribute data, it should be the containing element.

So in this case, you want the title property of the Book class to bind to the value of the title element, within the book-info element. Here's how you'd do that:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
    <map-to xml="book" />

    <field name="Title" type="java.lang.String">
      <bind-xml name="title" node="element" location="book-info"
    </field>
  </class>
</mapping>

It's then trivial to add another field mapping for the ISBN of the book:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
    <map-to xml="book" />

    <field name="Title" type="java.lang.String">
      <bind-xml name="title" node="element" location="book-info" />
    </field>
    <field name="Isbn" type="java.lang.String">
                <bind-xml name="isbn" node="element" location="book-info" />
                </field>
  </class>
</mapping>

At this point, you have the properties of the Book class all set. So on to the Author class...


Mapping additional classes

Mapping additional classes is done the same way as mapping the base class. The only difference is you don't need to use a map-to element in additional classes.

Mapping the Author class

You have everything you need to handle the mapping of the fields in the Author class to the author element. Remember, this is the XML fragment you work with:

<author>
  <name first="Lincoln" last="Child" />
 </author>

The only wrinkle is that instead of an element containing the first name and last name, you've got a single element with two attributes. But you already used the location attribute—which you need to specify that Castor should look at the name element for its data—and the node attribute, where you can indicate that the data you want is on an attribute instead of an element. So here's what you need in your mapping file:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" 
          "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
    <map-to xml="book" />

    <field name="Title" type="java.lang.String">
      <bind-xml name="title" node="element" location="book-info" />
    </field>
    <field name="Isbn" type="java.lang.String">
      <bind-xml name="isbn" node="element" location="book-info" />
    </field>
  </class>

  <class name="ibm.xml.castor.Author">
                <field name="FirstName" type="java.lang.String">
                <bind-xml name="first" node="attribute" location="name" />
                </field>
                <field name="LastName" type="java.lang.String">
                <bind-xml name="last" node="attribute" location="name" />
                </field>
                </class>
</mapping>

This should look pretty straightforward at this point. You indicate the class to map data to— Author —and the properties to map that exist on that class— FirstName and LastName. For each property, you specify the element to look at— name for both—and that you want an attribute.

Linking the Book and Author classes

If you take a close look at the XML shown above, you might notice that you don't tell Castor what XML element the Author class should map to. That's a problem, as Castor won't make any assumptions for you; once you introduce a mapping file, it's best to specify everything for Castor.

If you had a single author for each book, you'd probably have an Author property in the Book class. And given that, you could insert XML like this into your mapping:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" 
          "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
    <map-to xml="book" />

    <field name="Title" type="java.lang.String">
      <bind-xml name="title" node="element" location="book-info" />
    </field>
    <field name="Isbn" type="java.lang.String">
      <bind-xml name="isbn" node="element" location="book-info" />
    </field>

    <field name="Author" type="ibm.xml.castor.Author">
                <bind-xml name="author" />
                </field>
  </class>

  <class name="ibm.xml.castor.Author">
    <field name="FirstName" type="java.lang.String">
      <bind-xml name="first" node="attribute" location="name" />
    </field>

    <field name="LastName" type="java.lang.String">
      <bind-xml name="last" node="attribute" location="name" />
    </field>
  </class>
</mapping>

In this case, you include the mapping with the book section of the mapping file, because you map a property that belongs to the Book class. The type of the mapping is specified as ibm.xml.castor.Author, and the XML element named author is specified. Then, Castor's mapping system uses the definition of the Author class, within the class element, to handle the properties of an author.

The problem with all of this, of course, is that there is not a single Author property in the Book class. Instead, there's an Authors property that contains a collection of Author instances. So you must tell Castor about mapping each author element into an instance of Author (which is almost complete), and then combine each instance into the Authors property of Book.


Mapping elements into a collection

With the book/author situation, you need to map several elements—each author element in the XML document—into a collection, and then assign that collection to the Authors property of Book.

Start with the field element, because you are indeed mapping to a field of Book. You can also specify the value of the name attribute as "Authors", since that's the name of the property you'll bind to within Book:

<field name="Authors">
</field>

Next, you need to supply the type of the property. At first thought, you might easily suppose this is a collection type. However, you really want to indicate the type of each member of the collection (I'll piece together the collection part of this puzzle in a moment). So the type here should be ibm.xml.castor.Author. You'll have instances of the ibm.xml.castor.Author class that you want Castor to put into the Authors property:

<field name="Authors" type="ibm.xml.castor.Author">
</field>

Now here's the key: Indicate that this property is a collection by using the collection attribute. The value of this attribute is the type of collection. Currently, Castor supports only two values here: vector for list types, and array for array types. The first is accessed through the standard Java collections API with calls like next(); the second is managed like a Java array, and accessed by index like ar[2]. For your purposes, use vector, since your Java type is a List:

<field name="Authors" type="ibm.xml.castor.Author" collection="vector">
</field>

When you specify the collection attribute, Castor realizes that it should build the collection with values that correspond to the type attribute. So here, the Authors property should be a collection of instances of type ibm.xml.castor.Author.

All that's left, then, is to indicate the source for getting those instances of Author. That's done with a familiar element, the bind-xml element:

<field name="Authors" type="ibm.xml.castor.Author" collection="vector">
  <bind-xml name="author" />
</field>

And that's it; you have a complete mapping file. Your final file should look like Listing 6.


Listing 6. Completed mapping file
                
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" 
          "http://castor.org/mapping.dtd">

<mapping>
  <class name="ibm.xml.castor.Book">
    <map-to xml="book" />

    <field name="Title" type="java.lang.String">
      <bind-xml name="title" node="element" location="book-info" />
    </field>
    <field name="Isbn" type="java.lang.String">
      <bind-xml name="isbn" node="element" location="book-info" />
    </field>

    <field name="Authors" type="ibm.xml.castor.Author" collection="vector">
      <bind-xml name="author" />
    </field>
  </class>

  <class name="ibm.xml.castor.Author">
    <field name="FirstName" type="java.lang.String">
      <bind-xml name="first" node="attribute" location="name" />
    </field>

    <field name="LastName" type="java.lang.String">
      <bind-xml name="last" node="attribute" location="name" />
    </field>
  </class>
</mapping>


Using a mapping file programmatically

All that's left is to use the mapping file in your unmarshalling process. Previously, you used the Unmarshaller class statically, calling Unmarshaller.unmarshal() to convert from XML to Java code. Since you're using a mapping file, though, you'll need to create an instance of Unmarshaller and set some options. Listing 7 shows a class that handles unmarshalling from an XML document to Java objects.


Listing 7. Unmarshalling with a mapping file
                
package ibm.xml.castor;

import java.io.FileReader;
import java.util.Iterator;
import java.util.List;

import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Unmarshaller;

public class BookMapUnmarshaller {
 
  public static void main(String[] args) {
    Mapping mapping = new Mapping();

    try {
      mapping.loadMapping("book-mapping.xml");
      FileReader reader = new FileReader("book.xml");
      Unmarshaller unmarshaller = new Unmarshaller(Book.class);
                unmarshaller.setMapping(mapping);
      Book book = (Book)unmarshaller.unmarshal(reader);
      System.out.println("Book ISBN: " + book.getIsbn());
      System.out.println("Book Title: " + book.getTitle());
      List authors = book.getAuthors();
      for (Iterator i = authors.iterator(); i.hasNext(); ) {
        Author author = (Author)i.next();
        System.out.println("Author: " + author.getFirstName() + " " +
                                        author.getLastName());
      }
    } catch (Exception e) {
      System.err.println(e.getMessage());
      e.printStackTrace(System.err);
    }
  }
}

Compared to the unmarshaller talked about in the last two articles, the changes here are minimal. First, an instance of Unmarshaller is created, with an argument of Book.class. That tells the unmarshaller the top-level class it will unmarshall to. Note that this top-level Java object corresponds to the mapping element that uses the map-to element. Then, the mapping is set, and finally, a non-static version of unmarshal() is called.

And that's it! Nothing largely different than what you already know. In fact, as an exercise, why don't you try to write the code for marshalling from Java code to XML yourself? Refer to the BookMarshaller class from the last article, make the changes to set the mapping file, and you'll go from XML to Java code and back again in no time.


Conclusion

Data binding is ultimately about focusing on your data, rather than the format that data is stored in. Working with Java objects is simply for most Java programmers, and data binding makes it equally simply to get data from various sources—and in particular, XML—into those Java objects. And mapping in the data binding world takes that further: When you can populate your Java objects, you get greater flexibility in the data source formats. So if you like data binding, you'll love mapping; it lets you bind XML documents that don't quite match up to the naming conventions you want, or that you use a slightly different structure than your Java objects.

The same is true for those of you who are on the data wrangling side of things. You can get the data you need from Java classes, without having to build an intermediate layer when this method is called and stored in that oddly-named XML-esque variable, or where one XML document has multiple elements that all map to the same class. Again, the emphasis is on flexibility, and being able to do what you want with your data, rather than being bound by a framework or tool.


What's next?

You've seen what Castor has to offer in the XML world. That's merely scratching the surface of the API's capabilities, though. In the next article, you'll push past simple XML data binding and examine the SQL data binding facilities of Castor. You'll quickly move data from Java classes into your SQL database and back again, without JDBC. Get familiar with XML, brush up on your SQL, and come back next month for even more data binding power.

By the time you're done with the next article—the final piece in this series—you'll be able to convert between XML, Java, and SQL databases, all with the same API. That adds even more flexibility than your mapping files. With a single API—and similar calls for all data storage formats—you can work with databases, Java objects, and XML documents. In fact, for those of you who might sneak into the C# world from time to time, it sounds a lot like LINQ, the newest and one of the hottest technologies in Visual C# 2008. And it's all available now, in Java technology, in a stable API. Pretty nice, huh? So go forth, bind data, and see what you can do. Enjoy, and I'll see you online.



Download

DescriptionNameSizeDownload method
Article sample codex-xjavacastor3-Code.zip46KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

  • Java and XML, Third Edition (Brett McLaughlin and Justin Edelson, O'Reilly Media, Inc.): Covers XML from start to finish, including extensive information on data binding and mapping.

  • Java and XML Data Binding (Brett McLaughlin, O'Reilly Media, Inc.): In this older book, find details on Castor and the concepts involved in data binding.

  • Castor Professional Services: Hunting for paid support or help with Castor? Look into Castor's professional services.

  • IBM trial software: Build your next development project with trial software available for download directly from developerWorks.

Discuss

About the author

Photo of Brett McLaughlin

Brett McLaughlin is a bestselling and award-winning non-fiction author. His books on computer programming, home theater, and analysis and design have sold in excess of 100,000 copies. He has been writing, editing, and producing technical books for nearly a decade, and is as comfortable in front of a word processor as he is behind a guitar, chasing his two sons around the house, or laughing at reruns of Arrested Development with his wife. His last book, Head First Object Oriented Analysis and Design, won the 2007 Jolt Technical Book award. His classic Java and XML remains one of the definitive works on using XML technologies in the Java language.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Java technology
ArticleID=283839
ArticleTitle=Data binding with Castor, Part 3: Map between schemas
publish-date=01292008
author1-email=brett@newInstance.com
author1-email-cc=dwxed@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers