Search code examples
xml-serializationxstream

How to conditionally serialize a field (attribute) using XStream


I am using XStream for serializing and de-serializing an object. For example, a class named Rating is defined as follows:

Public Class Rating {

  String id;
  int score;
  int confidence;

  // constructors here...
}

However, in this class, the variable confidence is optional.

So, when the confidence value is known (not 0), an XML representation of a Rating object should look like:

<rating>
<id>0123</id>
<score>5</score>
<confidence>10</confidence>
</rating>

However, when the confidence is unknown (the default value will be 0), the confidence attribute should be omitted from the XML representation:

<rating>
<id>0123</id>
<score>5</score>
</rating>

Could anyone tell me how to conditionally serialize a field using XStream?


Solution

  • One option is to write a converter.

    Here's one that I quickly wrote for you:

    import com.thoughtworks.xstream.converters.Converter;
    import com.thoughtworks.xstream.converters.MarshallingContext;
    import com.thoughtworks.xstream.converters.UnmarshallingContext;
    import com.thoughtworks.xstream.io.HierarchicalStreamReader;
    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
    
    public class RatingConverter implements Converter
    {
    
        @Override
        public boolean canConvert(Class clazz) {
            return clazz.equals(Rating.class);
        }
    
        @Override
        public void marshal(Object value, HierarchicalStreamWriter writer,
                MarshallingContext context) 
        {
            Rating rating = (Rating) value;
    
            // Write id
            writer.startNode("id");
            writer.setValue(rating.getId());
            writer.endNode();
    
            // Write score
            writer.startNode("score");
            writer.setValue(Integer.toString(rating.getScore()));
            writer.endNode();
    
            // Write confidence
            if(rating.getConfidence() != 0)
            {
                writer.startNode("confidence");
                writer.setValue(Integer.toString(rating.getConfidence()));
                writer.endNode();
            }
        }
    
        @Override
        public Object unmarshal(HierarchicalStreamReader arg0,
                UnmarshallingContext arg1)
        {
            return null;
        }
    }
    

    All that's left for you to do is to register the converter, and provide accessor methods (i.e. getId, getScore, getConfidence) in your Rating class.

    Note: your other option would be to omit the field appropriately.