In this recipe, we are going to learn how to serialize a Groovy Bean into XML and back. Groovy Beans are discussed in detail in the Writing less verbose Java Beans with Groovy Beans recipe from Chapter 3, Using Groovy Language Features. The steps from this recipe can be applied either to POJO or POGO.
Groovy doesn't have a default XML object serializer. The groovy.xml.MarkupBuilder
is an excellent tool for generating XML in a fluent way but doesn't offer any simple mechanism to create an XML document out of bean properties.
There is, on the other hand, a large offer of third-party Java libraries for XML serialization. In this recipe, we are going to look at XStream (http://xstream.codehaus.org/). XStream is a very popular library, with frequent releases and a dead-simple API. Did we mention XStream is also fast and has a ridiculously low memory footprint?
The following steps offer an insight into how to achieve our task:
@Grab('com.thoughtworks.xstream:xstream:1.4.3') import com.thoughtworks.xstream.* import com.thoughtworks.xstream.io.xml.*
import groovy.transform.TupleConstructor @TupleConstructor class Customer { Long id String name String lastName Address businessAddress } @TupleConstructor class Address { String street String postcode String city String country }
The @TupleConstructor
annotation is mentioned in the Writing less verbose Java Beans with Groovy Beans from Chapter 3, Using Groovy Language Features.
def xstream = new XStream() def john = new Customer( 100, 'John', 'Red', new Address( 'Ocean Drive 101', '33139', 'Miami', 'US' ) ) def xmlCustomer = xstream.toXML(john) println xmlCustomer
<Customer> <id>100</id> <name>John</name> <lastName>Red</lastName> <businessAddress> <street>Ocean Drive 101</street> <postcode>33139</postcode> <city>Miami</city> <country>US</country> </businessAddress> </Customer>
Very cool indeed.
def xstream = new XStream(new DomDriver()) Customer johnred = xstream.fromXML(xmlCustomer) println johnred.id println johnred.businessAddress.postcode
100 33139
Whenever XStream encounters an object that needs to be converted to/from XML, it delegates to a suitable converter implementation associated with the class of that object.
XStream comes bundled with many converters for common types, including primitives, string, collections, arrays, null, date, etc. XStream also has a default converter that is used when no other converters match a type. This uses reflection to automatically generate the XML for all the fields in an object.
If an object is composed of other objects, the converter may delegate to other converters.
With XStream, it is also possible to drive the way the XML gets generated through aliases. There are different types of aliasing that can be applied to the serialization engine.
xstream.alias('Person', Customer)
The serialization process generates the following XML:
<Person> <id>100</id> <name>John</name> ... </Person>
xstream.aliasField('customer-id', Customer, 'id')
This changes the element name id
into customer-id
:
<Customer> <customer-id>100</customer-id> ... </Customer>
id
field an attribute of the <Person>
element. It couldn't be easier:xstream.useAttributeFor(Customer, 'id')
The resulting serialized XML looks like:
<Person id="100"> <name>John</name> </Person>
The documentation for XStream is extremely good, and if you want to use this tool to its full potential, it is recommended to spend some time reading the manual at http://xstream.codehaus.org/.