Omit Unexpected XML Elements With XStream

XStream is a Java xml library, which nicely serializes Java objects to XML and vice versa. It can easily deal with missing (i.e. optional) XML elements. The corresponding Java fields will just be left blank.

<user>
    <name>Peter Voss<name>
</user>

can be read into the Java object:

public class User {
    private String name;
    private String role;

    // getter and setter methods are here
}

In this case the optional <role> field is missing in the XML and the corresponding field in the User Java object will be left null when deserializing the XML.

But once if you have decided on your XML API, you might want to question if it is flexible enough. Just consider you have built software based on this XML spec. Can you still add optional XML elements without breaking the applications that you have already shipped? Consider you want to add more information, like a <department> element. Will your clients be able to just ignore this piece of information? The short answer is: No. XStream will throw a ConversionException if it finds an element that has no corresponding Java field. The Jira ticket XSTR-30 is an improvement request related to this topic. But so far XStream has no simple switch to turn off complaining about unknown elements.

But you could easily tweak XStream to ignore additional elements by adding your own custom mapper that ignores the field. The following snippet creates an XStream instance that ignores additional fields. It is grabbed from the CustomMapperTest.testCanBeUsedToOmitUnexpectedElements() unit test that is part of the XStream source code:

XStream xstream = 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);
      }
    };
  }
};

I just wanted to write this down, because a solution for this common problem is somewhat difficult to find right now.

About these ads

33 comments so far

  1. kali on

    excellent job.
    saved my day.
    thanks

  2. Mark on

    Thanks a lot :)

  3. Laure on

    Thanks, works fine !

  4. Mark on

    You just saved my day with this nifty trick, thnx!

  5. Sandy on

    Fantastic! Proved very useful. This saved time, as I wasn’t required to map all elements in first go.

  6. Tony on

    This doesn’t work for me. I still get the same error message when unknown XML elements pop up.

  7. David Bridgewater on

    Thank you so much for documenting this: really helpful.

  8. Sharath on

    Very Helpful

  9. Salman on

    Thanks dude!

    I still hope they introduce some configuration to Ignore Unexpected elements :)

  10. Daniel on

    Thanks this was great.

    I did have 1 problem, i had an implicit collection and it prevented it from parsing it.

    I tweaked your code to this:
    if (definedIn == Object.class && !fieldName.equals(“item”)) {
    return false;
    }

    is there a better way?

  11. Ara Bulbulian on

    Doesn’t seen to work well if your base class includes a List of ‘defined class’ elements. Those will improperly defined as Object.class.

  12. Daniel on

    Thanks, you just saved me a lot of time.

  13. Josep Prat on

    Thanks! It worked perfectly!

  14. Lee on

    Thanks for that, extremely helpful!

  15. Luke on

    Exactly what I was hoping to find!

  16. Brian Davis on

    Thank you for posting this, it was incredibly helpful.

  17. Ofer on

    thanks a lot. was very helpful.

  18. Alberto on

    nice!!!. Helped a lot!

  19. Spencer Stejskal on

    thank you good sir! very helpful

  20. Nick on

    Thanks for this! Daniel, I added to your suggestion as I was also having trouble with implicit fields. Rather than just hardcoding it, you can overload addImplicitCollection and keep track yourself (with a TreeSet member variable or whatever):

    @SuppressWarnings(“rawtypes”)
    @Override
    public void addImplicitCollection(Class ownerType, String fieldName,
    String itemFieldName, Class itemType) {
    implicitFields.add(fieldName);
    super.addImplicitCollection(ownerType, fieldName, itemFieldName, itemType);
    }

    // Then in shouldSerializeMember:
    if (!implicitFields.contains(fieldName) && definedIn.equals(Object.class))
    return false;

  21. Junior on

    Very good!

  22. arminr on

    Mate…A big thank you from Australia!

  23. RobertB on

    Big thanks from The Netherlands

  24. Igor on

    Big thanks from Israel!

  25. Gary on

    Big thanks from Scotland!

  26. Vinod on

    Thank you Daniel. We’ve been using this quiet sometime now. Recently we ran into some performance issues and we profiled our application.

    We were surprised to notice that shouldSerializeMember method was using up almost 9-15% of CPU time, almost equalling CPU utilization of our core ebusiness logic.

    The reason is that, we have a reasonalbly complex XML structure and the method has to recurse to get to the innermost element, increasing CPU utilization.

    I would recomend this solution for a simple XML structure.

    Working on an alternate solution. Will update, if I get ti done.

  27. Ian on

    Very very helpful. Thanks!

  28. Thomas on

    Great hint.
    We needed that exactly that functionality and i didn’t find it in the API.

  29. Korinth on

    Very insightful of you to lift this problem.

    We’ve always used parameters for selecting added elements in our service responses in order to manage this, thus not allowing to set fields that are not backward compatible unless explicitly stated. The solution you suggest is much more intuitive.

    Since you wrote this, has there been an update of XStream where it can actually be configured as default?

    • Peter Voss on

      Hi Martin,

      thanks for your feedback. I didn’t follow the recent developments of XStream, but I am not aware of an update in this area.

      –Peter

  30. TwiceCircled (@TwiceCircled) on

    Good work! Thank you, really excellent SEO title meant I could find this straight from Google.

  31. Mike the Monkey on

    Thanks helped me a bunch too

  32. Victor Williams Stafusa da Silva on

    To handle this shortcoming, XStream 1.4.5 added two new methods called ignoreUnknownElement (without parameters and with a String parameter).


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: