Search code examples
attributesxstreamoption-type

How to handle optional attribute with XStream


I would like to know how I can implement optional attributes within XStream.

Here is the XML:

<AttributeValues>
   <AttributeValue attributeId='id01' languageId='en'>20</AttributeValue>   
   <AttributeValue attributeId='id02'>99</AttributeValue>
   <AttributeValue attributeId='id03' languageId='en'78</AttributeValue>
   <AttributeValue attributeId='id04' languageId='en'>14</AttributeValue>
   <AttributeValue attributeId='id05'>9</AttributeValue>
</AttributeValues>

After the parsing process, not every 'AttributeValue' item has a languageId.

XStream sets such empty values to 'null'. But I would like to have it as an empty string "".

How do I implement this?


Solution

  • You can achieve your goal using custom Converter class.

    There will be a bit of guessing here since you haven't posted code for AttributeValues and AttributeValue class. I will use following classes:

    AttributeValues class:

    import com.thoughtworks.xstream.annotations.XStreamAlias;
    import com.thoughtworks.xstream.annotations.XStreamImplicit;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @XStreamAlias("AttributeValues")
    public class AttributeValues
    {
        @XStreamImplicit(itemFieldName="AttributeValue")
        public List<AttributeValue> Values;
    
        public AttributeValues()
        {
            Values = new ArrayList<AttributeValue>();
        }
    
        public void add(String id, String lg, String value)
        {
            AttributeValue item = new AttributeValue();
            item.attributeId = id;
            item.languageId = lg;
            item.value = value;
            Values.add(item);
        }
    }
    

    AttributeValue class:

    import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
    
    public class AttributeValue
    {
        @XStreamAsAttribute
        public String attributeId;
        @XStreamAsAttribute
        public String languageId;
        public String value;
    }
    

    And here is AttributeValueConverter class:

    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 AttributeValueConverter implements Converter
    {
        public boolean canConvert(Class clazz) {
            return AttributeValue.class == clazz;
        }
    
        public void marshal(Object object, HierarchicalStreamWriter hsw, MarshallingContext mc) {
            AttributeValue av = (AttributeValue) object;
            hsw.addAttribute("attributeId", av.attributeId);
            hsw.addAttribute("languageId", av.languageId);
            hsw.setValue(av.value);
        }
    
        public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) {
            AttributeValue av = new AttributeValue();
            av.attributeId = hsr.getAttribute("attributeId");
            av.languageId = hsr.getAttribute("languageId");
            if (av.languageId == null) av.languageId = "";
            av.value = hsr.getValue();
            return av;
        }
    
    }
    

    Serialization:

        AttributeValues obj = new AttributeValues();
        obj.add("id01", "en", "20");
    
        XStream xstream = new XStream();
        xstream.autodetectAnnotations(true);
        xstream.registerConverter(new AttributeValueConverter());
        String s = xstream.toXML(obj);
    

    Unserialization:

        XStream xstream = new XStream();
        xstream.autodetectAnnotations(true);
        xstream.registerConverter(new AttributeValueConverter());
        AttributeValues newobj = (AttributeValues)xstream.fromXML(s);