Serialising Objects to XML with Java, Groovy and XStream

From bemoko developer wiki

Jump to: navigation, search


XStream provides a handy way of going from XML to Objects and back again. This article gives a quick example showing how you can use it within bemokoLive.

Full source for this example is located at http://code.google.com/p/bemoko/source/browse/#svn/sites/examples/trunk/xstream

Step 1 : Create your Site Configuration

Create your site-config.xml to config configuration, plugins, intents and logging for this example:

<?xml version="1.0" encoding="UTF-8"?>
<site>
  <config>
    <source file="examples~xstream.cfg"/>
  </config>
  <content-sources>
    <source name="proxy" plugin="XmlProxy"/>
  </content-sources>
  <intents>
    <intent name="i" view="index.html"/>
  </intents>
  <logging>
    <priority value="DEBUG" expr="!config.prod" showLocation="true"/>
    <priority value="INFO" expr="config.prod"/>
   </logging>  
</site>

Step 2 : Create And Register Some Site Custom Configuration

Create the file conf/examples~xstream.cfg which configures the a tmp.directory configuration property which we'll use in the plugin in the next step:

tmp.directory = System.getProperty("java.io.tmpdir")

Step 3 : Create The Plugins

Create two domain objects, plugins/domain/Group.groovy

class Group {
  def name
  def people = []
}

and plugins/domain/Person.groovy

class Person {
  def name
  int age
}

and then create a plugin to read serialise and deserialise objects to and from XML

import com.bemoko.live.platform.Bemoko
import com.thoughtworks.xstream.XStream
import domain.Group
import domain.Person
 
@Grab(group='com.thoughtworks.xstream', module='xstream', version='1.3')
@Grab(group='xpp3', module='xpp3_min', version='1.1.3.4.O')
class XmlProxy {
  def log = Bemoko.log
  def model
  def action  
  @Lazy objectXmlFile = new File("${Bemoko.config.tmp.directory}/example-xstrema-object.xml")
 
  void execute(Map p) {
    action = p.action ?: "load"
    if (log.debugEnabled) log.debug("Action = ${action}")
    switch (action) {
      case ("load") :
        model = getGroupFromXml()
        break
      case ("create") :
        model = createXmlFromGroup(
          new Group( name : "mygroup",
            people : [
              new Person (name : "Bob",   age : 24),
              new Person (name : "Jane",  age : 29),
            ]
          )
        )
        break
    }    
  }
 
  def getXml() {
    return objectXmlFile.text
  }
 
  def createXmlFromGroup(group) {
    objectXmlFile.withOutputStream { out ->
      new XStream().toXML(group, out)
    }
  }
 
  def getGroupFromXml() {
    if (objectXmlFile.exists()) {
      objectXmlFile.withInputStream { input ->
        return new XStream().fromXML(input)
      }
    }
  }
}

Step 4: Render the Page

Then create a simple HTML template to render this content at ui/root/index.html:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>XStream example</title>
  </head>
  <body>
    <h1>XStream example</h1>
    <p>See <a href="http://xstream.codehaus.org/">XStream for more details on XStream</a></p>  
    [#switch content.proxy.action]
      [#case "load"]
        <div>XML Loaded</div>
        [#if content.proxy.model??]
          [#assign group = content.proxy.model]
          <div>
            Group name : ${group.name}
            <ul>
            [#list group.people as person]
              <li>name : ${person.name} (${person.age})</li>
            [/#list]
            </ul>
          </div>
        [#else]
          <div>XML not yet created, please click <a href="/i/action/create">here</a> to create</div>
        [/#if]
        [#break]
      [#case "create"]
        <div>XML Created</div>
        <div style="margin:20px;font-size:10pt">
          ${content.proxy.xml}
        </div>
        [#break]
    [/#switch]
    <hr/>
    <div>
      <div><a href="/i/action/load">Load XML to Object</a></div>
      <div><a href="/i/action/create">Create XML from Object</a></div>
    </div>
    <hr/>
    <div>File = ${content.proxy.objectXmlFile}</div>    
  </body>
</html>

Step 5 : Access your site

Go to the i intent on you site, e.g. http://localhost:8080/live/examples/xstream/i, and click on the link to create the XML from the object. You should see that the Group object gets serialised down to XML. Now when you click on load you should see the object read back from XML.

This is a very light weight of loading XML into objects which can be used to render in a bemokoLive site. Have a look on the XStream web site if you want any more information on how to to use XStream.