Skip to content

XMLMapper fails to deserialize null (POJO reference) from blank tag #318

@joschi

Description

@joschi

I'm using XmlMapper to deserialize XML documents from some external sources and map them to predefined POJOs.

When Jackson encounters a blank tag (not empty, but only whitespace characters), I would expect it to deserialize it into a null reference or an equivalent empty collection, depending on the configuration of the XmlMapper.

Unfortunately, Jackson fails with a MismatchedInputException. Enabling DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT on the XmlMapper doesn't help either.

Is there a configuration flag which would make XmlWrapper interpret the blank tag as empty and deserialize it into null?

Jackson version: 2.9.7

Test case for reproduction:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;

public class DescriptionTest {
    private final XmlMapper mapper = new XmlMapper();

    @Test
    public void emptyString() throws IOException {
        String s = "<wrapper>"
                + "  <id>id</id>"
                + "  <nested></nested>"
                + "</wrapper>";

        Wrapper value = mapper.readValue(s, Wrapper.class);
        Assert.assertEquals("id", value.id);
        Assert.assertNull(value.nested);
    }

    @Test
    public void blankString() throws IOException {
        String s = "<wrapper>"
                + "  <id>id</id>"
                + "  <nested>    </nested>"
                + "</wrapper>";

        // This fails with the following exception:
        // com.fasterxml.jackson.databind.exc.MismatchedInputException:
        // Cannot construct instance of `JacksonXMLTest$Nested` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('    ')
        Wrapper value = mapper.readValue(s, Wrapper.class);
        Assert.assertEquals("id", value.id);
        Assert.assertNull(value.nested);
    }

    @Test
    public void blankString2() throws IOException {
        String s = "<wrapper>"
                + "  <id>id</id>"
                + "  <nested>    </nested>"
                + "</wrapper>";

        // This fails with the following exception:
        // com.fasterxml.jackson.databind.exc.MismatchedInputException:
        // Cannot construct instance of `JacksonXMLTest$Nested` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('    ')
        ObjectMapper mapperCopy = mapper.copy().enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        Wrapper value = mapperCopy.readValue(s, Wrapper.class);
        Assert.assertEquals("id", value.id);
        Assert.assertNull(value.nested);
    }

    @Test
    public void missing() throws IOException {
        String s = "<wrapper>"
                + "  <id>id</id>"
                + "</wrapper>";

        Wrapper value = mapper.readValue(s, Wrapper.class);
        Assert.assertEquals("id", value.id);
        Assert.assertNull(value.nested);
    }

    @Test
    public void validStructure() throws IOException {
        String s = "<wrapper>"
                + "  <id>id</id>"
                + "  <nested>"
                + "    <nested2 attr=\"test\"><![CDATA[Some text]]></nested2>"
                + "  </nested>"
                + "</wrapper>";

        Wrapper value = mapper.readValue(s, Wrapper.class);
        Assert.assertEquals("id", value.id);
        Assert.assertEquals("test", value.nested.nested2.attr);
        Assert.assertEquals("Some text", value.nested.nested2.value);
    }


    static class Wrapper {
        @JacksonXmlProperty(localName = "id")
        String id;
        @JacksonXmlProperty(localName = "nested")
        Nested nested;
    }

    static class Nested {
        @JacksonXmlProperty(localName = "nested2")
        Nested2 nested2;
    }

    static class Nested2 {
        @JacksonXmlProperty(localName = "attr", isAttribute = true)
        String attr;
        @JacksonXmlText
        String value;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions