XStream: Basic Built-in Converters

In the previous tutorials we saw an example of how to convert java object to XML and back. That tutorial also explained the concept of aliases and implicit collection.In the last tutorial we show how to write a custom converter. In this tutorial, lets see some of the basic built in converters of XStream and how the resultant XML from those converters look like. We will look at how the following types are converted.

XStream: Custom Converter for BufferedImage

In the previous tutorials we saw an example of how to convert a java object to XML and back. That tutorial also explained the concept of aliases and implicit collection. While serializing a Java object to XML XStream uses custom converters. These converters specify how to create XML from a Java Object or how to create a Java Object from XML elements. In most cases the provided converters should suffice, however, in certain cases you may want to create your own converters. To do so create a class that implements com.thoughtworks.xstream.converters.Converter and implement the void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context); and Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context); The example below demonstrates a CustomConverter. To make the example more interesting we will write a converter to serialize a BufferedImage. The image for the example can be downloaded from here

XStream: Referencing Objects

XStream allows you to store references while converting a java object to XML. Consider a case where you have an Artist Object. The object contains albums that the artist has released, but you also want to store a reference to a ‘similar artist’. People listening to an artist might be interested in listening to a similar artist. When you convert this object to XML, XStream preserves the reference to the similar artist. It also manages circular references, so if there are no similar artist then the ‘similar artist’ field could store a reference to the Owner Artist.

XStream has multiple ways to store references. you need to use the setMode(int mode) method to set the mode. XStream allows following modes:

  • NO_REFERENCES
  • ID_REFERENCES
  • XPATH_RELATIVE_REFERENCES
  • XPATH_ABSOLUTE_REFERENCES
  • SINGLE_NODE_XPATH_RELATIVE_REFERENCES
  • SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES

XStream: Handling Attributes in XML

In the previous tutorial we saw how to convert Java to XML and back. In this tutorial we look at different ways to handle XML attributes using XStream. However note that the attributes are only safe if you know that the written String values are not affected by the XML parser’s white space normalization. The XML specification requires that a parser does this and it means that an attribute value of:

<element attr="  foo\t\n   bar    ">
</element>

will always be normalized and passed this assertion:

assertEquals("foo bar", element.getAttr());
XStream has no influence about this behavior.

XStream: Java to XML Using Annotation

In the previous tutorials we saw an example of how to create a java object from XML. That tutorial also explained the concept of aliases and implicit collection. In this tutorial we continue with that but use annotation on the java class. The advantage with annotation is that it is faster to code and develop. the disadvantage is that you bind the java class to XStream.

In the example below we convert an object of type JazzArtist to XML. JazzArtist contains fields name, isAlive, a url and a list of albums. This example uses the following annotations

  • @XStreamAlias - Used on the type, field or attribute. To understand ‘aliases’ look at this tutorial
  • @XStreamImplicit - Used on Collections or array. To understand ‘Implicit Collections/Arrays’ look at the this tutorial.
  • @XStreamAsAttribute - Used to mark a field as an attribute.
  • @XStreamConverter - Use a specific converter for this field. We will look at Converters in detail in a later tutorial. In this example we use a Boolean converter for ‘isAlive’ field, we want the XML to have values yes or no instead of true or false.

XStream: Java to XML

In the previous example we saw how to convert a Java Object to XML and back. In this example we look at another example of Java Object to XML Conversion. The example uses an object called a ‘JazzArtist’. This object has a list of ‘Album’ objects besides some other properties. We see here another example of Alias and implicit collection. (To understand alias and implicit collections look at this tutorial) We divide the example in three parts. In the first part we do not use aliases or implicit collections. In the second part we use aliases and in the third part we use an implicit Collection. Note the output from the three parts and observe how aliases and implicit collection change the way the output xml looks.

package com.studytrails.xml.xstream;

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.XStream;

public class CreateXMLFromMusicArtistObject {

    public static void main(String[] args) {
        CreateXMLFromMusicArtistObject marshaller = new CreateXMLFromMusicArtistObject();
        marshaller.createXMlFromObject();
        marshaller.createXMLFromObjectUsingAlias();
        marshaller.createXMLFromObjectUsingAliasAndImplicitCollection();
    }

XStream: XML To Java

In the earlier tutorial we looked at a way to convert Java to XML and back. In this tutorial we look at some more examples of XML To Java Conversion. XStream can convert XML elements to multiple types depending on the type specified in the Java class. For example a series for similarly named elements can be converted to an array of String, a List of String or an enum. XStream uses an appropriate Converter based on type specified in the java class. Lets look at some examples.

In this first example we have an XML that has a parent element called ‘Music’. It has a child element called type. We populate a Music object that has a ’type’ field which is an enum.

package com.studytrails.xml.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;

public class ConverterExample3 {
    static String xml1 = "<Music><type>rock</type></Music>";

    public static void main(String[] args) {
        XStream xStream = new XStream();
        xStream.processAnnotations(Music.class);
        Music musicObject = (Music) xStream.fromXML(xml1);
        System.out.println(musicObject);
        // prints Music [type=ROCK]
    }

}

@XStreamAlias("Music")
class Music {
    public enum genre {
        ROCK, JAZZ
    };

    genre type;

    @Override
    public String toString() {
        return "Music [type=" + type + "]";
    }

}     

XStream: Java to XML and Back

The Problem Statement

XStream can be used to convert a Java Object to XML and back. This tutorial aims to create a java representation of the BBC RSS. We will start with a Simple java class and gradually start adding complexity to it so that it can be converted to the BBC RSS. Note that if you are looking at a way to parse an XML, it would be a good idea to first build a java class that XStream can convert to the required XML. XStream can then use the same class to deserialize the XML. First, have a look at the BBC RSS. Your browser would have formatted it to html so look at the source to see the XML. The parent element is ‘rss’. It has a child element called ‘channel’. The ‘channel’ has some properties (title, link, image etc) and a list of news ‘item’(s). Each ‘item’ has properties set on it (title, description etc). The aim is to create a Java class that XStream can convert to the BBC RSS.

Creating an XStream Instance

The first step is to create an instance of com.thoughtworks.xstream.XStream. This class is a facade to the XStream API and provides all major functionalities. If this class does not solve your problem then you could directly call the API methods. After obtaining the instance of XStream use the fromXML method to convert the XML to a java object. Note that creating an XStream instance is an expensive operation. It is therefore advisable to create a proper instance once and then reuse it for multiple calls (even in parallel). The setup is not threadsafe but any subsequent marshalling/unmarshalling is threadsafe.