Search code examples
javajacksonjackson-dataformat-xml

Deserialize inner portion of XML into new class instance


Given XML in the following (simplified) format:

<outer><inner><field1>a</field1><field2>b</field2><field3>c</field3></inner></outer>

I'd like to deserialize the <inner> element into a class representing that and discard the rest.

public class Inner {
    private String field1;
    private String field2;
    private String field3;
    // getters, setters, ctor
}

I am using the Jackson XmlMapper class to perform the deserialization. If I strip <outer> out of the xml string obviously it works.

XmlMapper xmlMapper = new XmlMapper();
// in my scenario the `<inner>` element actually contains fields I don't care about
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Inner inner = xmlMapper.readValue(xml, Inner.class);
System.out.println(inner);
// Inner(field1=a, field2=b, field3=c)

If I leave the <outer> element all of the fields in inner are null.

I've tried annotating the Inner class with @JacksonXmlRootElement(localName = "inner") but that didn't change the output.

I could create a class that represents the <outer> element but that seems wasteful. I could probably also create a new string containing just the xml between the <inner> elements, but again that feels a bit hacky.

In my case the xml is being broadcast by a separate system that I have no control over, so I can simply amend the xml structure.

Is it possible to deserialize the "inner" xml into a new class instance?


Solution

  • It seems that for @JacksonXmlRootElement(localName = "inner") to work as you expect you also need UNWRAP_ROOT_VALUE. E.g.

    xmlMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    

    I can't say the above is very obvious from the docs.