Using Simple for XML serialization

Really does make it simple to go from Java objects to XML

Java™ developers have a variety of choices when it comes to serializing and deserializing Extensible Markup Language (XML) objects. Simple is one such example, and it offers a number of advantages over its competitors. Explore an introductory overview of how to use Simple within an XML communication system in this article.

Share:

Brian M. Carey, Senior Systems Engineer, Triangle Information Solutions

Photo of Brian CareyBrian Carey is an information systems consultant specializing in Java, Java Enterprise, PHP, Ajax, and related technologies. You can follow Brian Carey on Twitter at http://twitter.com/brianmcarey.



24 November 2009

Also available in Chinese Japanese Portuguese

What is Simple?

Simple is a Java framework used to simplify the process of serializing and deserializing XML. Using Simple, developers can simplify (hence the name) the process of translating plain old Java objects (POJOs) into XML documents—a process known as serialization. Simple also facilitates the reverse: Developers can translate XML documents into POJOs—a process known as deserialization.

Simple lives up to its by name using annotations to enable the serialization or deserialization process. POJOs are annotated according to how the corresponding XML document should appear. Some fields are annotated as attributes. Other fields are annotated as elements. The class is usually annotated as the root element. The framework handles the tedious process of interpreting the annotations and producing a corresponding XML document during the serialization process. Not surprisingly, the annotations are also interpreted during the deserialization process when an XML document is translated into a POJO.

The use of Simple has several advantages. First, it facilitates rapid application development. Because Simple is so simple, it enables developers to quickly implement robust applications that use XML serialization and deserialization without committing to an excessive learning curve or development overhead.

Next, Simple requires no configuration. As mentioned previously, Simple uses annotations. These annotations are in lieu of the XML-based configuration files that typically accompany frameworks of this nature.

Finally, Simple adds only minimally to the footprint of applications that use it. The Java Archive (JAR) file is only 239 kilobytes. Simple is also not dependent upon a series of other JAR files, as is frequently the case with competing frameworks.

Obtaining Simple

Before using Simple, you must first obtain it by going to the Simple Web site listed in Resources and downloading the archive. However, there is good news and bad news regarding this process. The good news is that the archive is free. The bad news is that the archive is in .tar.gz format. So if you are relying on the Microsoft® Windows® native archive extractor to open this archive, you will be disappointed. You need WinZip or another similar archive utility.

After you extract the files, note that in the jar directory there is, not surprisingly, a JAR file (simple-xml-2.1.4.jar). This is the JAR file that is required in your classpath at compile time and runtime.

Serializing

Serializing an object into an XML document is a (surprise!) simple process. It involves two steps:

  1. Create the POJO with the appropriate annotations.
  2. Write the few lines of code that actually perform the serialization process.

For the purposes of this article, you revisit the familiar theme (familiar to readers of my articles, anyway) of fishing lures. So, Listing 1 is a POJO that represents information about fishing lures.

Listing 1. Lure class
@Root
public class Lure {

     @Attribute
     private String type;
	
     @Element
     private String company;
	
     @Element
     private int quantityInStock;
	
     @Element
     private String model;

     public String getType() {
		return type;
     }

     public void setType(String type) {
          this.type = type;
     }

     public String getCompany() {
          return company;
     }

     public void setCompany(String company) {
          this.company = company;
     }

     public int getQuantityInStock() {
          return quantityInStock;
     }

     public void setQuantityInStock(int quantityInStock) {
          this.quantityInStock = quantityInStock;
     }

     public String getModel() {
          return model;
     }

     public void setModel(String model) {
          this.model = model;
     }
}

There's really nothing complicated about this POJO. The only parts of it that might seem unfamiliar at first are the annotations. Again, this is intentional. Recall that the Simple framework is expected to live up to its name.

The @Root annotation describes the root element of the XML document. Because every XML document requires a root element, it is important that you include this.

The @Attribute annotation above the type field identifies that field as an attribute. This attribute is added as an attribute to the root element.

The rest of the annotations are @Element annotations. These occur just above three fields: company, quantityInStock, and model. These fields represent elements within the XML document.

The rest of the POJO is comprised of accessors and mutators in accordance with JavaBean standards.

Now that the POJO is complete, it's time to write the serialization code. See Listing 2 for that code.

Listing 2. LureExample class
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          Lure lure = new Lure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
		
          File result = new File("lure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

The first thing you do is instantiate a Persister object. Note that this class is part of the Simple framework and implements the Serializer interface.

Next, you instantiate the Lure object and set the fields appropriately. In this case, the name of the company that manufactures the lure is Donzai The name of the model is Marlin Buster. The quantity in stock is 23. Finally, the type of lure is Trolling.

Next, you instantiate a File object with the name of the file that will be the XML document. In this case, that name is lure.xml.

Finally, you invoke the serializer to write the file. There are two parameters provided in the write() method. The first parameter is the POJO. The second parameter is the File object.

Now you can execute this code. Listing 2 is a Java application, so you can use your favorite integrated development environment (IDE) to run it. Make sure that simple-xml-2.1.4.jar is in your classpath. If you are using Eclipse, you can simply right-click on the file, select Run As, and then select Java Application from the menu that appears.

If everything worked (and it should have—this is simple, remember?), then the resulting XML document should look just like Listing 3.

Listing 3. LureExample output
<lure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

Notte a couple things about Listing 3. First, note that the lure type is an attribute of the root element. This makes perfect sense because you annotated the type field in the POJO with @Attribute as opposed to @Element.

Another important point about the resulting XML is that the element names follow the JavaBean standards. For example, the root element is lure, even though the class name is Lure. The three child element names perfectly match the field names. Once again, this is pragmatic because you don't want the root element name in proper case while the children names follow a different pattern.

Deserializing

Because serializing an object is so easy, it should be easy to deserialize one too, right? Right!

Recall that deserialization is the process of translating an XML document into a POJO. The good news is that you can use the XML document you just created for this purpose.

Listing 4 shows the deserialization code.

Listing 4. LureExample2 class
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          File source = new File("lure.xml");
          Lure lure = serializer.read(Lure.class, source);

          System.out.println(lure.getCompany());
          System.out.println(lure.getModel());
          System.out.println(lure.getQuantityInStock());
          System.out.println(lure.getType());
     } catch (Exception e) {
          e.printStackTrace();
     }
}

Once again, you start by instantiating an object (Persister) which implements the Serializer interface.

Another familiar line is the instantiation of the File object. However, here there is a distinct difference. In Listing 3, you instantiated a File object for a file that didn't exist. Here, it is assumed (and, indeed, it must be the case) that the file does exist.

Next, you instantiate the POJO by invoking the read method from the Serializer object. The read method takes two parameters: the class of the POJO and the File object that represents the XML file containing the data.

Finally, you print out all the information from the POJO to ensure that everything was read correctly.

When you execute this code, your output should look like Listing 5.

Listing 5. LureExample2 output
Donzai
Marlin Buster
23
Trolling

Full tree serializations

Thus far, the XML document that you serialized and deserialized was fairly (here's a new word) simple.

Most XML documents are far more complicated. They usually have layers of nested elements and, in some cases, one to many repeated elements with several child elements each.

Fortunately, Simple continues to live up to its name even with more complex documents. It's as simple as nesting a POJO within a POJO. Take a look at Listing 6.

Listing 6. AdvancedLure class
@Attribute
private String type;

@Element
private String company;
	
@Element
private int quantityInStock;
	
@Element
private String model;
	
@Element
private ConfigurationScheme configurationScheme;

The AdvancedLure class in Listing 6 is strikingly similar to the Lure class described in Listing 1. The one exception is the inclusion of another field: configurationScheme. The configuration scheme is represented by another POJO that is described in Listing 7.

Listing 7. ConfigurationScheme class
@Root
public class ConfigurationScheme {
	
@Element
private String color;
	
@Element
private int size;

For the sake of brevity, I left out the accessors and mutators.

The annotations in Listing 7 should look familiar. They are the same annotations that were used in Listing 1.

And that brings you to Listing 8.

Listing 8. LureExample3 class
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          AdvancedLure lure = new AdvancedLure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
			
          ConfigurationScheme configurationScheme = new ConfigurationScheme();
          configurationScheme.setColor("Blue");
          configurationScheme.setSize(3);
          lure.setConfigurationScheme(configurationScheme);
			
          File result = new File("advancedlure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

The big difference between Listing 8 and Listing 2 is that you instantiate a ConfigurationScheme object and set the appropriate field in the AdvancedLure object.

Running this code, the output should look like Listing 9.

Listing 9. LureExample3 output
<advancedLure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
   <configurationScheme>
      <color>Blue</color>
      <size>3</size>
   </configurationScheme>
</advancedLure>

As you can see, the nested elements are serialized exactly as you expect.

Enumerations

Frequently, XML documents contain enumerations of certain elements. That is, the same element name repeats itself, albeit with different child or attribute data. Fortunately, Simple can handle this situation as well.

For the purpose of demonstrating this feature, you create a new class, called Inventory, that contains the name of the warehouse where the inventory is located and a list of lures found at that inventory location, as in Listing 10.

Listing 10. Inventory class
@Root
public class Inventory {
	
     @ElementList
     private List<AdvancedLure> lures;
	
     @Attribute
     private String warehouse;

Note that you use a new annotation: @ElementList. This annotation tells the Simple framework that the corresponding List object represents an enumeration of XML elements.

The code used to demonstrate the serialization of this POJO is just as easy as the code used to serialize a more compact POJO, such as the one serialized in Listing 2. The only added complexity comes in instantiating all the necessary objects for testing purposes. See Listing 11.

Listing 11. LureExample4 class
Serializer serializer = new Persister();

AdvancedLure lure = new AdvancedLure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
			
ConfigurationScheme configurationScheme = new ConfigurationScheme();
configurationScheme.setColor("Blue");
configurationScheme.setSize(3);
lure.setConfigurationScheme(configurationScheme);
			
			
AdvancedLure lure2 = new AdvancedLure();
lure2.setCompany("Ziggi");
lure2.setModel("Tuna Finder");
lure2.setQuantityInStock(44);
lure2.setType("Trolling");
		
ConfigurationScheme configurationScheme2 = new ConfigurationScheme();
configurationScheme2.setColor("Red");
configurationScheme2.setSize(5);
lure2.setConfigurationScheme(configurationScheme2);
			
List<AdvancedLure> lures = new ArrayList<AdvancedLure>();
lures.add(lure);
lures.add(lure2);
			
Inventory inventory = new Inventory();
inventory.setLures(lures);
inventory.setWarehouse("Midwest");
			
File result = new File("inventory.xml");

serializer.write(inventory, result);

When that code is executed, an XML file called inventory.xml is created. The contents of that file should look like Listing 12.

Listing 12. LureExample4 output
<inventory warehouse="Midwest">
   <lures>
      <advancedLure type="Trolling">
         <company>Donzai</company>
         <quantityInStock>23</quantityInStock>
         <model>Marlin Buster</model>
         <configurationScheme>
            <color>Blue</color>
            <size>3</size>
         </configurationScheme>
      </advancedLure>
      <advancedLure type="Trolling">
         <company>Ziggi</company>
         <quantityInStock>44</quantityInStock>
         <model>Tuna Finder</model>
         <configurationScheme>
            <color>Red</color>
            <size>5</size>
         </configurationScheme>
      </advancedLure>
   </lures>
</inventory>

As you can see, the output perfectly mimics the POJO that you instantiated and created in Listing 11. There are two advancedLure elements, and they each contain the data you used to populate the corresponding POJOs. Note that the nesting is appropriate too.

Constructors

It's possible that your code uses POJOs that are immutable. In this case, you might lack setter methods to modify field properties and, instead, rely on constructors to set these values. Simple can handle this situation as well.

In this case, the annotations are specified within the constructor parameters instead of above the field name. Annotations are also required above the appropriate accessor methods. See Listing 13.

Listing 13. Inventory2 class
public Inventory2(@ElementList(name="lures") List<AdvancedLure> lures, 
 @Attribute(name="warehouse") String warehouse) {
     this.lures = lures;
     this.warehouse = warehouse;
}

@ElementList(name="lures")
public List<AdvancedLure> getLures() {
     return lures;
}

@Attribute(name="warehouse")
public String getWarehouse() {
     return warehouse;
}

Note that when you specify the annotation as part of the constructor parameters you must also specify the field name to which it corresponds. In the case of the first parameter, the field name is lures. In the case of the second parameter, the field name is warehouse.

You then provide matching annotations and field names above the accessor methods. Just above the getter for lures, you can see the appropriate annotation, which perfectly matches the annotation used in the constructor. Similarly, the annotation above the getter for warehouse perfectly matches that annotation.

To execute this code, you modify Listing 11 just slightly to include the code in Listing 14.

Listing 14. LureExample5 class
Inventory2 inventory = new Inventory2(lures,"MidWest");

You use the code in Listing 14 instead of the setter methods that you used in Listing 11. Everything else remains the same.

Template filters

Another great feature of Simple is its ability to use template filters or default values when deserializing an XML document.

Go back to the original lure.xml, but modify it slightly, as in Listing 15.

Listing 15. Lure2.xml document
<lure type="Trolling">
   <company>${lure.company}</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

Notice how the company element does not contain the name of an actual company, but rather an Apache Ant-like variable declaration? In this case, the name of the variable is lure.company.

Template filters allow you to substitute that variable declaration with an actual value that you establish at runtime. One easy way to do that is with a Map object that associates the variable name with its value. You then use that Map object to construct a Filter object from the Simple framework. Then, construct the Persister object using that Filter object. Take a look at Listing 16.

Listing 16. LureExample6 class
Map<String,String> map = new HashMap<String,String>();
map.put("lure.company", "Monmouth");
Filter filter = new MapFilter(map);
			
Serializer serializer = new Persister(filter);
File source = new File("lure2.xml");

Lure lure = serializer.read(Lure.class, source);

System.out.println(lure.getCompany());
System.out.println(lure.getModel());
System.out.println(lure.getQuantityInStock());
System.out.println(lure.getType());

Listing 16 doesn't look a lot different than Listing 2. The main difference is that a HashMap is instantiated that associates a String value to a String key. The String key in this case is predictably lure.company, which is the variable name that you used in Listing 15. Here you give it a value of Monmouth as opposed to Donzai, which was the value in the XML document that you read earlier.

When this code is executed, the output should look like Listing 17.

Listing 17. LureExample6 output
Monmouth
Marlin Buster
23
Trolling

As you can see, the template filter substitutes the variable name lure.company with the actual value associated with that key name in the Map object. The output is exactly as expected.

Conclusion

As you have seen, Simple is a robust XML serialization and deserialization framework. It is easy to use, requires no configuration, and streamlines development.

There are many more powerful features of Simple. However, due to space constraints, only a few of them can be explored here. I highly recommend that developers who require XML serialization and deserialization within their software development initiatives consider Simple for that purpose.


Download

DescriptionNameSize
Source code for the examples used in this articleSimple.zip5KB

Resources

Learn

  • XML Tutorial: Try this tutorial on w3schools.com if you're just getting started with XML.
  • The Java Tutorials: Dig into the info on this site if you're just getting started with the Java programming language.
  • XML basics for new users: An introduction to proper markup (Kay Whatley, developerWorks, February 2009): If you're new to XML, this article introduces the basic construction of XML documents as well as the rules that you must follow to create well-formed XML, including naming conventions, proper tag nesting, attribute guidelines, declarations, and entities. You'll also gain an understanding of validation in terms of both DTD and schema usage.
  • Introduction to XML (Doug Tidwell, developerWorks, August 2002): Learn what XML is and why it was developed. In this tutorial, you also cover a variety of important XML programming interfaces and standards, and ends with two case studies showing how companies are using XML to solve business problems.
  • New to Java programming: Get an overview of Java technology basics and how the technology fits into contemporary software development. Investigate links to relevant introductory developerWorks content, other educational resources, plus IBM downloads and products.
  • New to XML: Visit this great starting point for resources available to XML developers on IBM developerWorks.
  • 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.
  • developerWorks podcasts: Listen to interesting interviews and discussions for software developers.

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Java technology, Open source
ArticleID=448255
ArticleTitle=Using Simple for XML serialization
publish-date=11242009