I have the following class:
import org.apache.commons.beanutils.BeanUtils;
import com.thoughtworks.xstream.XStream;
...
public class MyBean {
protected static final XStream XSTREAM = new XStream(new DomDriver());
protected String name;
protected Something something;
public MyBean() {
something = new Something();
}
public MyBean(String xml) {
this();
MyBean beanFromXML = (MyBean) XSTREAM.fromXML(new StringReader(xml));
BeanUtils.copyProperties(this, beanFromXML);
}
public String toString() {
return XSTREAM.toXML(this);
}
// Getters and setters...
}
It's a bean with ability to serialize and deserialize to/from XML using XStream.
I also added a non-args constructor that initializes something
, to avoid null pointer errors - the bean is actually a lot more complex, and I don't want to be checking "is something != null
?" a million times.
The problem arises when I use the XML-constructor. Lets say I've the following XML:
<myBean>
<name>John</name>
</myBean>
This is what I would like the constructor to do:
name: "John";
something: new Something();
However, since there is no <something>
element in the XML, BeanUtils.copyProperties makes something = null;
, thus what I get is:
name: "John"
something: null
How can I copy beanFromXML
's properties into this
... but ignoring the null properties instead of overwriting them?
You can create a custom converter that creates a default value for null properties:
public class MyNullConverter implements Converter {
@Override
public Object convert(final Class type, final Object value) {
try {
return value == null ? type.newInstance() : value;
} catch (final InstantiationException e) {
return null;
} catch (final IllegalAccessException e) {
return null;
}
}
}
Then register it for bean classes you want default (empty) values:
ConvertUtils.register(new MyNullConverter(), Something.class);
Your code will now work. The only thing that might bug you, is that your Something gets initialized twice. Don't know if this is OK...
BTW, if you want a more fine grained control over the process: use BeanUtilsBean, PropertyUtilsBean, and ConvertUtilsBean instead.