Search code examples
springxstream

XStreamMarshaller ignore unknown elements


After change data model on server side my XStream client throw Exception

com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field {fieldName}

To prevent this behavior I try to do something to ignore unknown elements. I am using XStreamMarshaller from Spring-oxm 4.0.5 and XStream 1.4.5. I known that since XStream version 1.4.5 is available method ignoreUnknownElements().

XStreamMarshaller marshaller = new XStreamMarshaller();
    marshaller.setStreamDriver(streamDriver);
    marshaller.setAutodetectAnnotations(autodetectAnnotations);
    marshaller.getXStream().ignoreUnknownElements();

Above solution doesn't work and I still get mentioned exception.

I have client side model copied from server. For example:

public class Device implements Serializable {

    protected String device_id;

    protected String device_model_code;

    protected String device_model_name;

    protected String device_name;

//getters, setters
}

If I comment field for example device_model I will have Exception

com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field device_name

How can I solve my problem? How can I implement XStreamMarshaller to ignore unknown elements?


Solution

  • First thing is that method ignoreUnknownElements() available since XStream 1.4.5 is only for marshaling not for unmarshaling. So it doesn't work if somebody adds a new field in data model on server side.

    To solve described problem you have to override protected method constructXStream() from org.springframework.oxm.xstream.XStreamMarshaller implementation:

    public class CustomXStreamMarshaller extends XStreamMarshaller {
    
    @Override
    protected XStream constructXStream() {
        // The referenced XStream constructor has been deprecated as of 1.4.5.
        // We're preserving this call for broader XStream 1.4.x compatibility.
        return new XStream() {
            @Override
            protected MapperWrapper wrapMapper(MapperWrapper next) {
                    return new MapperWrapper(next) {
                        @Override
                        public boolean shouldSerializeMember(Class definedIn, String fieldName) {
                            if (definedIn == Object.class) {
                                return false;
                            }
                            return super.shouldSerializeMember(definedIn, fieldName);
                        }
                    };
            }
        };
    }}
    

    You only need to use your own implementation in XStreamMarshaller declaration:

    CustomXStreamMarshaller marshaller = new CustomXStreamMarshaller();
        marshaller.setStreamDriver(streamDriver);
        marshaller.setAutodetectAnnotations(autodetectAnnotations);