Everyday Coder

eve·ry·day cod·er [ev-ree-dey koh-der, noun]
a person who designs, writes and tests computer programs daily

I am the type of developer that uses existing 3rd-party solutions whenever possible. Lately, I've been using XStream for object persistance in a standalone Java application. So far, I must say that I'm extremely impressed with how well this API is put together and also with its simplicity. Exporting an entire object tree is as simple as new XStream().toXML(myObjectTree);

One of the great features of XStream is its ability for customization of the XML. I began customizing my XML and ran into a slight snag (not a bug, but a snag). I couldn't figure out how to get an enum field to output as an attribute rather than a child element. Example Java class:

class Card {
int val;
Type type;

enum Type {
HEARTS, CLUBS, DIAMONDS, SPADES
}
}

Now let's export it:

void export(List<Card> cards) {
XStream xs = new XStream();
xs.alias("cards", List.class);
xs.alias("card", Card.class);
xs.useAttributeFor("val", int.class);
xs.useAttributeFor("type", Type.class);

System.out.print(xs.toXML(cards));
}

Executing the above code will produce the following XML:

<cards>
<card val="1">
<type>SPADES</type>
</card>
</cards>

As you can see, the type field is not properly used as an attribute like I instructed: xs.useAttributeFor("type", Type.class); The reason? Well, I wasn't sure, so, being the lazy developer I am, I trolled around Google, et. al. to find if someone else had this problem. Nothing. And after a few minutes of poking around in the XStream documentation, I was at a loss. I sent an email describing my problem to the users' mailing list, expecting to wait a day or so for an answer. Supprisingly, I recieved an answer within a few hours, from the project lead himself.

Jörg informed me that attribute converters must be of type SingleValueConverter. Attributes are single text values and don't need all of that other object (un)ravelling stuff. Jörg also pointed me to an issue that had been opened in the project's bug tracking system just a few days ago that also described this.

The solution, at the moment, is to simply create a specific converter for my Enum types that is a SingleValueConverter. The code for this is below:

public class SingleValueEnumConverter extends AbstractSingleValueConverter {

private final Class enumType;

public SingleValueEnumConverter(Class type) {
this.enumType = type;
}

public boolean canConvert(Class c) {
return c.equals(enumType);
}

public Object fromString(String value) {
return Enum.valueOf(enumType, value);
}
}

And to modify the XStream example above:

XStream xs = new XStream();
xs.alias("cards", List.class);
xs.alias("card", Card.class);
xs.useAttributeFor("val", int.class);
xs.useAttributeFor("type", Type.class);

xs.registerConverter(new SingleValueEnumConverter(Card.Type.class));

System.out.print(xs.toXML(cards));

And now the XML looks like this:

<cards>
<card val="1" type="SPADES"/>
</cards>

So as you can see, this was exactly what I needed. I love coding in a world where we have such a large community of people willing to take a few minutes of their time to guide you in the right direction. Great job XStream!

5 Responses to “Enum as an XML Attribute with XStream”

  1. on 17 Apr 2007 at 12:59 pm Mark

    Thank You

  2. on 10 Aug 2007 at 10:13 am Matthew

    My experience was identical to yours until I googled to find the solution and found your blog! Thanks for taking the trouble to write it all down…

  3. on 10 Aug 2007 at 4:39 pm Everyday Coder

    Glad I could help!

  4. on 12 Aug 2008 at 9:54 am Manjunath

    I am trying to show the XML tags with SPADES as the value for the second tag with an attribute inside one main tag.
    Something like
    tag1
    tag2 att1=”12″>value<end tag2
    end tag1

    Thanks
    Manjunath

  5. on 13 Aug 2008 at 4:31 am Manjunath

    The above problem can be solved by implementing convertor like:

    HierarchicalStreamWriter writer;
    writer.startNode(”tag-name”);
    writer.addAttribute(”attribute-name”, “att-value”);
    writer.setValue(”tag-value”);
    writer.endNode();

    with the above code you can get the attribute and value for a tag implementing Convertor.

    Thanks
    Manjunath

Trackback URI | Comments RSS

Post a Comment