XStream serialize null values

tweetysat picture tweetysat · Oct 25, 2012 · Viewed 10k times · Source

Suppose I have

class Student
{
String name;
int    age;
String teacher;
}

Then :

public class App1
{
    public static void main(String[] args)
    {
        Student st = new Student();
        st.setName("toto");

        XStream xs = new XStream();

        xs.alias("student",Student.class);

        System.out.println(xs.toXML(st));
    }

}

Gives me :

<student>
  <name>toto</name>
  <age>0</age>
</student>

Is there a way for dealing null values ? I mean :

<student>
  <name>toto</name>
  <age>0</age>
  <teacher></teacher>
</student>

It's possible if I do

st.setTeacher("");

but not if teacher is null.

I tried with a custom converter but it seems the null values are not sent to the converter.

Answer

PopStore picture PopStore · Jun 5, 2015

I'm using XStream 1.4.7, @XStreamAlias annotation for custom field names, @XStreamConverter for custom converters (to represent dates and other custom beans). However, a custom converter for null values was not even called. My goal was to serialize all the fields of the object, including the null ones, I didn't need to unmarshal XML.

I managed to do that by creating a custom ReflectionConverter. I extended ReflectionConverter from XStream library and overrode doMarshal method. The only thing I changed was calling writeField method for null info.values:

new Object() {
{
    for (Iterator fieldIter = fields.iterator(); fieldIter.hasNext();) {
        FieldInfo info = (FieldInfo) fieldIter.next();
        if (info.value != null) {
            //leave the code unchanged
            ...
        } else {
            //add this to write null info.value to xml
            Log.info("MyCustomReflectionConverter -> serialize null field: " + info.fieldName);
            writeField(info.fieldName, null, info.type, info.definedIn, info.value);
        }
    }
    //... leave the rest of the code unchanged
}
};

After that, I created xStream instance like that (it is very important to register your converter with very low priority):

StaxDriver driver = new StaxDriver(new NoNameCoder()) {
    @Override
    public StaxWriter createStaxWriter(XMLStreamWriter out) throws XMLStreamException {
        // the boolean parameter controls the production of XML declaration
        return createStaxWriter(out, false);
    }
};

XStream xStream = new XStream(driver);
xStream.autodetectAnnotations(true);//needed to process aliases
//register MyCustomReflectionConverter
MyCustomReflectionConverter reflectionConverter = new MyCustomReflectionConverter (xStream.getMapper(), new SunUnsafeReflectionProvider());
xStream.registerConverter(reflectionConverter, XStream.PRIORITY_VERY_LOW);

Thanks to Mark Nabours for his solution here

Hope it helps. Has anyone found a better solution for this?