Omit unexpected XML Elements with XStream

XStream is a great library to create XML from objects and vice-versa, and one of the many areas I use it is to store configurations. One problem is that XStream has the hability to ignore fields when serializing objects, but not the opposite – e.g., if it finds a tag that does not have a corresponding property in your class, it will throw an exception.

It is not clear to me why they still don’t have anything to handle such situation, which is fairly common to happen. For example, you may have a XML and only needs a small fraction of its data, or maybe you changed the way you store configurations and removed some properties. In both cases you will have to map the entire object graph, even if you don’t want it. Their FAQ page states this:

If a field is removed from the class, deserializing an old version that contains the field will cause an exception. Leaving the field in place but declaring it as transient will avoid the exception, but XStream will not try to deserialize it.

I find this behavior pretty odd and annoying, but luckily there is a workaround: the XStream class has a protected method named wrapMapper(MapperWrapper next) that subclasses may implement in order to tell the library if a given class or property should be considered. In this method you can add verifications for the fields or classes that you don’t want to bother, and return false for them.

Check out a working example:

XStream x = new XStream() {
	@Override
	protected MapperWrapper wrapMapper(MapperWrapper next) {
		return new MapperWrapper(next) {
			@Override
			@SuppressWarnings("rawtypes")
			public boolean shouldSerializeMember(Class definedIn, String fieldName) {
				if (fieldName.equals("shouldCopyWithProject")) {
					return false;
				}

				return super.shouldSerializeMember(definedIn, fieldName);
			}
		};
	}
};

In the previous example, I had a field named “shouldCopyWithProject” that was removed in newer versions of my application, but such refactoring resulted in crashes when opening the files from older versions of the app, so I had to handle the situation manually.

It would be great if XStream had a cleaner solution for this, but I think it is very unlikely to happen. Nevertheless, the approach here described works very well.

Update

As Chris have pointed out in the comments, it is much easier to just use the omitField(class, fieldName) method, as in

// .....
XStream x = new XStream();
x.omitField(A.class, "shouldCopyWithProject");
// .....

I came across this method several times, but for some reason I thought it only worked for serialization. Anyway, thanks to Chris for simplifying our lives :)