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 :)

4 thoughts on “Omit unexpected XML Elements with XStream

  1. Ouch, you’re right. For some reason I was only considering that method for serialization purposes. Thanks for the tip Chris, I updated the topic to include this information.

    • The omit method will work only when you know which fields are extra. In case I am deserialization a third-party xml which can be subject to change, I dont know at compile time which potential fields can come.

  2. You probably thought you can’t deserialize with it because that’s what the documentation says! For omitField():

    Prevents a field from being serialized. To omit a field you must always provide the declaring type and not necessarily the type that is converted.

    I will confirm myself whether this actually does work for deserialization…

Leave a Reply

Your email address will not be published. Required fields are marked *

*


five + 7 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>