Apache XMLBeans is an open source, XML- and Java™-binding tool used to generate Java classes and interfaces from an XML schema. With the generated beans, you can parse or generate XML documents that conform to the schema. Consequently, this binding causes a very tight coupling between the generated Java classes and the XML schema. When you make minor or major changes to the XML schema, the beans are regenerated and the new beans corresponding to the changed XML schema are used. At least, this is how it's intended to work. Unfortunately, sometimes an application needs to support multiple versions of a schema. For example, in the case where XML is used as a standard for data exchange, the application must provide backward or forward compatibility to older or newer versions of the standard.
Consider an employee data management application, in which the application takes the
employee information in the form of an XML file and uses Apache XMLBeans to process
it. The employee data has been defined by an XSD, shown in Listing 1. This schema is
compiled with the XMLBeans schema compiler. The application then uses the generated Java classes and
interfaces to process an incoming XML document that
is compliant to the XSD with the namespace com.ibm.sample.employee:1.
Listing 1. First version of the employee XML schema
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="com.ibm.sample.employee:1" elementFormDefault="qualified"
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="com.ibm.sample.employee:1">
<element name="employee" type="tns:employeeType"></element>
<complexType name="employeeType">
<sequence>
<element name="firstName" type="string"></element>
<element name="lastName" type="string"></element>
<element name="department" type="string"></element>
<element name="phone" type="string"></element>
<element name="eEmail" type="string"></element>
</sequence>
</complexType>
</schema>
|
Listing 2 shows the application that processes the employee XML, and Listing 3 shows the client application that uses it:
Listing 2. The XMLBeans application
public class EmployeeApplication {
public void parseXML(String xmlFileName){
EmployeeDocument employeeDoc =
EmployeeDocument.Factory.parse(new File(xml));
EmployeeType employee = employeeDoc.getEmployee();
System.out.println(employee.getFirstName());
// Do something more useful with the employee data
}
}
|
Listing 3. The client
EmployeeApplication app = new EmployeeApplication();
app.parseXML(xmlFilePath);
|
Now assume the schema is modified, and the Java beans generated for the old schema can
no longer use the new schema to process the XML. Listing 4 shows the changed schema
with some new elements added, and the namespace changed to com.ibm.sample.employee:2 to indicate it is the second version.
Listing 4. Second version of the employee XML schema
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="com.ibm.sample.employee:2" elementFormDefault="qualified"
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="com.ibm.sample.employee:2">
<element name="employee" type="tns:employeeType"></element>
<complexType name="employeeType">
<sequence>
<element name="firstName" type="string"></element>
<element name="lastName" type="string"></element>
<element name="dept" type="string"></element>
<element name="eMail" type="string"></element>
<element name="phone" type="string"></element>
<element name="address" type="tns:addressType"></element>
</sequence>
</complexType>
<complexType name="addressType">
<sequence>
<element name="streetName" type="string"></element>
<element name="houseNumber" type="string"></element>
<element name="city" type="string"></element>
<element name="state" type="string"></element>
<element name="zipCode" type="string"></element>
</sequence>
</complexType>
</schema>
|
To ensure forward compatibility, you don't want to modify the client application. However, some sources of the input XML have upgraded to the new schema, so the application must be able to process incoming employee XML data with either namespace. But XMLBeans can't manage the competing schemas, so what can you do?
Overcoming the processing limitation
For the application to be able to process the new XML schema, you'll have to generate a
new set of Java beans that corresponds to the new schema. Because you do not wish to alter
the application, you need to make sure the new Java beans generated by Apache XMLBeans
have the same package names as the old ones. That way, the application can use these
beans without any change in the code. Map both the com.ibm.sample.employee:1 and
com.ibm.sample.employee:2 namespaces to a single Java
package, such as com.ibm.sample.employee. (Mapping is outside the scope of this article; see Resources for more information.)
Once you have different sets of Java beans to correspond to the different schemas, all you do is load the appropriate one depending on the incoming XML. You can use dynamic class loading techniques to ensure the correct set of beans is loaded. The following sections show how to use the proxy pattern and Java class loading to load multiple versions of the XMLBeans corresponding to each of the schemas.
In Java programming, class loaders are first-class objects and have their own
namespace. A class loaded by a class loader instance is uniquely identified by that
class loaders namespace and the class name. For example, suppose you have a class
loader called MyClassLoader. If an instance of this class loader, myLoaderA, loads a class Foo, and the same class Foo is also loaded by another instance, myLoaderB, the JVM treats the class Foo as two different classes and loads it twice (see Figure 1).
Figure 1. Java class loading

Java class loading uses a delegation model to load the classes. Every class loader has a parent class loader, which delegates the searching and loading of a class to its parent (parent-first delegation) before it attempts to load the class itself. When there is a hierarchy of class loaders, the root class loader, which is the bootstrap class loader, attempts to load the class first. If it cannot, its child, the system class loader, tries to load it, and so on. (See Resources for more information on Java class loading.)
To process two different schema versions, you will create different class loader instances and have each one of them load the application and a version of the Java beans, corresponding to an XML schema.
Next, you will create a proxy with the same public interface as the original
application or bean. The proxy will create one instance of a class loader for each XML
schema version. The parent of this class loader will be the class loader of the
current thread context. Based on the schema of the XML being processed, this proxy
will use the appropriate instance of the class loader to load the Java beans
corresponding to each XSD and the application itself. The reason for loading the
application multiple times is that when the JVM attempts to load all the classes used
by the application, it looks for them in the same namespace. If it doesn't find these
classes in the same namespace, it throws a ClassNotFound exception. Figure 2 shows how the proxy works:
Figure 2. Dynamic loading of the XMLBeans by the proxy

The proxy can use the namespace of the received XML to decide which XMLBeans to load, or the XML can have an element that will indicate the version of the XSD. The proxy can then use a simple SAX parser to retrieve this information.
Sample application processing multiple schema versions
Revisit the employee data management application. Listing 5 shows the proxy code:
Listing 5. The proxy
/* These are class variables as only one set of instances of the
* class loaders are required.
* Using instance variables will only proliferate the class loaders and
* the classes loaded by them.
*/
private static URLClassLoader ccl1 = null, ccl2 = null;
private URLClassLoader createURLClassLoader(URL url){
ClassLoader parent = Thread.currentThread().getContextClassLoader();
URLClassLoader ucl = new URLClassLoader(new URL[]{applicationJarURL,url},
parent);
return ucl;
}
private URLClassLoader loadXMLBeans(int choice) {
try{
switch (choice){
case 1:
if ( ccl1 == null){
ccl1 = createURLClassLoader(
new URL("file",null,jarPath+"employee1.jar"));
}
return ccl1;
// Load the latest by default
default :
case 2:
if ( ccl2 == null){
ccl2 = createURLClassLoader(
new URL("file",null,jarPath+"employee2.jar"));
}
return ccl2;
}
public void parseXML(String xmlFileName){
try {
// Determine which version of XML schema is being used.
URLClassLoader ccl = loadXMLBeans(choice);
Class c = ccl.loadClass(
"com.ibm.sample.application.employee.EmployeeApplication");
Class s = String.class;
Object obj = c.newInstance();
Method m = c.getDeclaredMethod("parseXML", new Class[]{s});
m.invoke(obj,new Object[]{xmlFileName});
}
|
In this listing, the Java beans for the XSD with namespace com.ibm.sample.employee:1 have been archived into a JAR file called
employee1.jar, and the Java beans for the XSD with namespace com.ibm.sample.employee:2 have been archived into a JAR file called
employee2.jar. At run time, neither the JAR files nor the class files of the
application itself are included in the classpath, as they will be loaded from within
the proxy by an instance of the URLClassLoader. If these
classes are available in the classpath, the parent of the URLClassLoader instance, which is the system class loader, will load
them. Also, you will not be able load multiple versions of these JAR files as the classes will all be in the system class loaders namespace.
The proxy determines which version of the XML schema the input XML is using; based on
that, it then creates an instance of the URLClassLoader and
adds the URL of the appropriate JAR file to the classpath of the URLClassLoader. Once the proxy obtains the appropriate instance of
the class loader, it uses Java reflection to invoke the corresponding method of the
original application (or bean). Here, we use reflection because we have loaded the application using a class loader that is not the system class loader.
Now the employee data management application can process employee data that conforms to either of the XML schemas. Listing 6 shows the code that will use the proxy to invoke the application:
Listing 6. Modified client application
// Create an instance of the proxy instead of the employee application
EmployeeApplicationProxy app = new EmployeeApplicationProxy();
app.parseXML(xmlFilePath);
|
In this example, the application remained unchanged. But in some cases, you might have to change the application as some new processing is required to process the XML data that conforms to new schema (such as address) in the sample. As a result, you need to manage two sets of application code. In such a case, you can load different versions of the applications (or portions of it) along with the Java beans of a particular version of the XSD. The advantage of this solution is that you can minimize the application changes, and easily manage the application when you have frequent schema changes. Also, it's easy to add or remove support for schema versions.
As you can see, even without support for multiple schemas, you can use XMLBeans for XML processing and still be able to manage schema variations. We hope you'll try this technique in your own work.
| Description | Name | Size | Download method |
|---|---|---|---|
| Source code sample | x-xmlbeans-SampleApplication.zip | 10KB | HTTP |
Information about download methods
Learn
- Apache XMLBeans Web site: Learn how to generate JavaBeans components for a given XML schema.
- Classes and class
loading (Dennis Sosnoski, developerWorks, April 2003): Find more information on how Java class loading works.
- Understanding
Extension Class Loading: Explore Sun's tutorial on Java class loading basics.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- The technology
bookstore: Browse for books on these and other technical topics.
- developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- IBM
trial software for product evaluation: Build your next project with trial software available for download directly from developerWorks, including application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- XML zone discussion forums: Participate in any of several XML-related discussions.
- developerWorks XML zone: Share your thoughts: After you read this article, post your comments and thoughts in this forum. The XML zone editors moderate the forum and welcome your input.
- developerWorks blogs: Check out these blogs and get involved in the developerWorks community.

Abdul Rasid is a System Software Engineer with IBM India Software Labs, Bangalore. He currently works on the WebSphere RFID Information Center development team.

Pallavi Nagesha Rao has worked in the IT industry for over eight years in a variety of roles, including the development of J2EE applications, transaction management systems (TXSeries), and information management systems. Currently, she leads the WebSphere RFID Information Center development at India Software Labs. She has also authored other developerWorks articles and Redbooks.
Comments (Undergoing maintenance)





