Java Tip 138: Still parsing to generate your JavaBeans' XML representation?

Delegate this job to a JavaBean-XML mapping component

The portability and extensibility of both Java and XML make them ideal choices for the flexibility and wide availability requirements of Web applications and services. SAX (Simple API for XML), DOM (Document Object Model), XSL (Extensible Stylesheet Language), XSLT (XSL Transformations), SOAP (Simple Object Access Protocol), and BML (Bean Markup Language) are some of the buzzwords associated with XML. This tip brings together the benefits of Java and XML without forcing developers to understand all XML-related buzzwords.

By using Remote Method Invocation (RMI) in distributed Java application development, no low-level socket or network communication code is involved. The code remains at a higher level, leveraging its use of RMI classes. Similar gain comes with the use of Enterprise JavaBeans (EJB) technology, freeing developers from several low-level coding aspects (transaction, recovery, and activation). With this tip's JavaBean-XML mapping component, developers don't directly deal with XML-related APIs.

Note: You can download this tip's source code from Resources.

Write the component

The BeanXMLMapping component converts a JavaBean to an XML document and vice versa. By using JavaBean introspection, XML parsers, and DOM APIs, you can develop this component with a toXML() method to represent the received bean as an XML document and a fromXML() method to instantiate and populate the proper bean according to the XML document received.

Listing 1 shows a possible implementation for the BeanXMLMapping component. This particular implementation uses the JOX (Java Objects in XML) library. You can develop other implementations of this component using other APIs. I selected JOX for its simple, reusable solution.

Listing 1. BeanXMLMapping component

import com.wutka.jox.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class BeanXMLMapping {
  /**
   *  Retrieves a bean object for the
   *  received XML and matching bean class
   */
  public static Object fromXML(String xml, Class className) {
    ByteArrayInputStream xmlData = new ByteArrayInputStream(xml.getBytes());
    JOXBeanInputStream joxIn = new JOXBeanInputStream(xmlData);
    try {
      return (Object) joxIn.readObject(className);
    } catch (IOException exc) {
      exc.printStackTrace();
      return null;
    } finally {
      try {
        xmlData.close();
        joxIn.close();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
  /**
   *  Returns an XML document String for the received bean
   */
  public static String toXML(Object bean) {
    ByteArrayOutputStream xmlData = new ByteArrayOutputStream();
    JOXBeanOutputStream joxOut = new JOXBeanOutputStream(xmlData);
    try {
      joxOut.writeObject(beanName(bean), bean);
      return xmlData.toString();
    } catch (IOException exc) {
      exc.printStackTrace();
      return null;
    } finally {
      try {
        xmlData.close();
        joxOut.close();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
  /**
   *  Find out the bean class name
   */
  private static String beanName(Object bean) {
    String fullClassName = bean.getClass().getName();
    String classNameTemp = fullClassName.substring(
        fullClassName.lastIndexOf(".") + 1,
        fullClassName.length()
        );
    return classNameTemp.substring(0, 1)
         + classNameTemp.substring(1);
  }
}

The BeanXMLMapping class converts a JavaBean to and from an XML document and provides two methods:

  • toXML(): generates the respective XML document String for the bean instance
  • fromXML(): creates a bean instance for the XML document String

Use the component

Listing 2 shows AccountHistoryContext, a bean class empowered with toXML() and fromXML() capabilities. The JavaBean class simply delegates its toXML() and fromXML() methods to the BeanXMLMapping component.

Listing 2. AccountHistoryContext bean

public class AccountHistoryContext{
  private String dateFrom;
  public String getDateFrom()  { return dateFrom; }
  public void setDateFrom(String s)  { dateFrom = s;  } 
  ...
  // Other attributes with their get and set methods
  public String toXML()   {
    return BeanXMLMapping.toXML(this);
  }
  public static AccountHistoryContext fromXML (String xml)   {
      return (AccountHistoryContext)  
        BeanXMLMapping.fromXML (
           xml, AccountHistoryContext.class);
  }
}

Figure 1 represents the mapping between a generic JavaBean class and its respective generic XML document.

Figure 1. JavaBean-XML document mapping. Click on thumbnail to view full-size image.

JavaBean to XML

The XML document's first line is the XML declaration, which defines the document's XML version. In this case, the document conforms to XML Specification 1.0 (<?xml version="1.0" encoding="ISO-8859-1"?>).

The next line defines the document's first element (the root element). This is the JavaBean name (<Bean>).

The next lines define the root's (JavaBean's) child elements. These are the bean attributes available through get methods. If the attribute is a basic type (e.g., String, int), a node with the attribute name is generated. If a bean has a get method for a nested bean, nested child elements are generated.

Figure 2 shows a ContactInfo bean object, its class, and the XML document generated by the toXML() method invocation.

Figure 2. toXML() method invocation

XML to JavaBean

When reading the XML document, a mapping between the root node name, attributes, and nested nodes will be made for the bean, set methods, and nested beans, respectively. Empty constructors for each bean and set methods for each attribute (basic type or nested bean) must be provided to accomplish the proper mapping.

Figure 3 shows a ContactInfo XML document, a matching ContactInfo bean class, and the bean object resulting from the fromXML() method invocation.

Figure 3. fromXML() method invocation

Usage example

Let's examine an example of BeanXMLMapping usage. The sample consists of XML, JavaBean classes, and snapshots of an online banking application. You can download the example source code from Resources.

Figure 4 is a sample account history page in an online banking application.

Figure 4. Sample account history page

Figure 5 displays the AccountHistory bean class diagram, while Listing 3 shows an XML document generated through its toXML() method invocation.

Figure 5. AccountHistory bean class diagram. Click on thumbnail to view full-size image.

Listing 3. Account history XML representation

<?xml version="1.0" encoding="ISO-8859-1"?>
<AccountHistory>
  <transactionList>
    <transaction>
      <deposit></deposit>
      <withdraw>-,150.00 </withdraw>
      <date>3/10/2002 </date>
      <description>Check Number: 213 </description>
      <balance>,340.50</balance>
    </transaction>
    <transaction>
      <deposit></deposit>
      <withdraw>-51.50</withdraw>
      <date>3/7/2002</date>
      <description>ATM Withdrawal 350 SAN JOSE CA</description>
      <balance>,189.00</balance>
    </transaction>
    <transaction>
      <deposit>,060.40 </deposit>
      <withdraw></withdraw>
      <date>3/5/2002</date>
      <description>ACH DEPOSIT - MyCompany </description>
      <balance>,249.40</balance>
    </transaction>
    <transaction>
      <deposit></deposit>
      <withdraw>-0.00</withdraw>
      <date>2/26/2002</date>
      <description>JC'S BBQ AND DELI SAN JOSE CA </description>
      <balance>,229.40</balance>
    </transaction>
  </transactionList>
  <accountHistoryContext>
    <account>
      <holder>Paulo Caroli</holder>
      <type>checkings</type>
      <number>316614-10</number>
    </account>
    <dateTo>Monday, March 11, 2002 </dateTo>
    <dateFrom>Monday, February 25, 2002 </dateFrom>
  </accountHistoryContext>
</AccountHistory>

Figure 6's sequence diagram shows a possible scenario where an AccountHistory bean object is reached and its toXML() method invoked.

Figure 6. Simplified sequence diagram for getting AccountHistory XML document. Click on thumbnail to view full-size image.

Figure 7 is a sample page for requesting account history in an online banking application. The bank account and dates are retrieved and displayed on this page; Listing 4 shows how such information can be represented as XML.

Figure 7. Sample page for requesting account history in an online banking application

Listing 4. Account history context XML representation

<?xml version="1.0" encoding="ISO-8859-1"?>
<AccountHistoryContext>
  <account>
    <holder>Paulo Caroli</holder>
    <type>checkings</type>
    <number>316614-10</number>
  </account>
  <dateTo>Monday, March 11, 2002 </dateTo>
  <dateFrom>Monday, February 25, 2002 </dateFrom>
</AccountHistoryContext>

AccountHistoryContext.FromXML() is invoked to retrieve the AccountHistoryContext bean object for the respective XML document.

Keep it simple!

Fortunately, it is this simple. Conversion from JavaBean to XML and vice versa happens smoothly, without requiring much from the JavaBean code. Developers can benefit from the use of the BeanXMLMapping component and code at a high level without dealing with any XML-specific library.

There's no need for complexity to accomplish JavaBean-XML mapping. Take advantage of the BeanXMLMapping component and enjoy your XML-empowered beans.

Paulo Caroli is a project manager at Omni Pros. Paulo has a master's degree in software engineering and is a Sun Certified Architect for Java Technology with more than nine years of experience in application development. He is an expert in object-oriented techniques who specializes in Java 2 Platform, Enterprise Edition (J2EE) Web application development.

Learn more about this topic