Skip to content

No String-argument constructor/factory method to deserialize from String value when it is a Integer #254

@mrdgsmith

Description

@mrdgsmith

I am trying to deserialise the following xml into the objects:

<?xml version="1.0" encoding="iso-8859-1" ?>
<foo>
    <dean>
        <bar>28</bar>
        <bar>31</bar>
    </dean>
</foo>

My classes are the following

public class Foo {

    private final Dean dean;

    public Foo(@JacksonXmlProperty(localName = "dean") final Dean dean) {
        this.dean = dean;
    }

    public Dean getDean() {
        return dean;
    }
}`
public class Dean {

    @JacksonXmlElementWrapper(useWrapping = false)
    private final List<Bar> bar;

    public Dean(@JacksonXmlProperty(localName = "bar") final List<Bar> bar) {
        this.bar = bar;
    }

    public List<Bar> getBar() {
        return bar;
    }
}
public class Bar {

  @JacksonXmlText
    private Integer value;

    public Bar(@JacksonXmlProperty(localName = " ") Integer value) {
        this.value = value;
    }


    public Integer getValue() {
        return value;
    }
}

My mapper dependencies are the following:

ext {
    jacksonVersion = "2.8.9"
}
compile(group: "com.fasterxml.jackson.dataformat", name: "jackson-dataformat-xml", version: "$jacksonVersion")
compile(group: "com.fasterxml.jackson.datatype", name: "jackson-datatype-jsr310", version: "$jacksonVersion")

Here is the failing test with exception being thrown by the xmlMapper

@Test
    public void shouldParseAndCreateObject() throws Exception {
        final JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
         XmlMapper xmlMapper = (XmlMapper) new XmlMapper(jacksonXmlModule)
                .disable(FAIL_ON_UNKNOWN_PROPERTIES, FAIL_ON_IGNORED_PROPERTIES);
        Foo foo = xmlMapper.readValue("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>\n" +
                "<foo>\n" +
                "    <dean>\n" +
                "        <bar>28</bar>\n" +
                "        <bar>31</bar>\n" +
                "    </dean>\n" +
                "</foo>", Foo.class);
        assertThat(foo.getDean().getBar().get(0).getValue(), is(28));
    }
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of Bar: no String-argument constructor/factory method to deserialize from String value ('28')
 at [Source: out/test/resources/test.xml; line: 4, column: 16] (through reference chain: service.Foo["dean"]->service.Dean["bar"]->java.util.ArrayList[0])

From reading the exception it looks like the mapper is treating the value 28 as a string rather than a Integer but if i change the Bar class to the following and add an attribute to element bar to the raw xml the same test passes.

public class Bar {

    private String test;

    @JacksonXmlText
    private Integer value;

    public Bar(@JacksonXmlProperty(localName = "test", isAttribute = true) String test, @JacksonXmlProperty(localName = " ") Integer value) {
        this.test = test;
        this.value = value;
    }

    public String getTest() {
        return test;
    }

    public Integer getValue() {
        return value;
    }
<?xml version="1.0" encoding="iso-8859-1" ?>
<foo>
    <dean>
        <bar test="haha1">28</bar>
        <bar test="haha2">31</bar>
    </dean>
</foo>
@Test
    public void shouldParseAndCreateObject() throws Exception {
        final JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
         XmlMapper xmlMapper = (XmlMapper) new XmlMapper(jacksonXmlModule)
                .disable(FAIL_ON_UNKNOWN_PROPERTIES, FAIL_ON_IGNORED_PROPERTIES);
        Foo foo = xmlMapper.readValue("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>\n" +
                "<foo>\n" +
                "    <dean>\n" +
                "        <bar test=\"haha1\">28</bar>\n" +
                "        <bar test=\"haha2\">31</bar>\n" +
                "    </dean>\n" +
                "</foo>" +
                "</foo>", Foo.class);
        assertThat(foo.getDean().getBar().get(0).getValue(), is(28));
    }

I would say that the Mapper should infer the type from the constructor parameter type and try to instantiate that object with the string value and under the hood do something like Integer.valueOf("28")

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