Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem deserializing POJO with unwrapped List, ignorable attribute value #301

Closed
JulienHoueix opened this issue Jul 18, 2018 · 6 comments
Closed
Milestone

Comments

@JulienHoueix
Copy link

Hello,

I encountered a bug during XML deserialization with Jackson 2.9.6

If I have a parent class that :

  • contains a list of objects with a specific name
  • and also contains another list of different objects which contain a value with that same name

I get the following error when I try to serialize the XML :

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.Double out of START_OBJECT token
at [Source: (StringReader); line: 1, column: 44] (through reference chain: ch.hcuge.deja.drug.client.Parent["CHILDB"]->java.util.ArrayList[0]->ch.hcuge.deja.drug.client.ChildB["MY_PROPERTY"])

But I have this error only if the parent object contains an attribute!

I have a test case that shows the problem :

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import org.junit.Test;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

public class TestBug {

    // Succeeds
    @Test
    public void testWithoutAttribute() throws Exception {
        StringWriter stringWriter = new StringWriter();
        stringWriter.append("" +
                "<PARENT>" +
                "  <CHILDB>" +
                "    <MY_PROPERTY>12.34</MY_PROPERTY>" +
                "  </CHILDB>" +
                "</PARENT>");
        XmlMapper xmlMapper = new XmlMapper();
        Parent deserializedParent = xmlMapper.readValue(stringWriter.toString(), Parent.class);
    }

    // Fails!
    @Test
    public void testWithAttribute() throws Exception {
        StringWriter stringWriter = new StringWriter();
        stringWriter.append("" +
                "<PARENT>" +
                "  <CHILDB MY_ATTR=\"TEST_VALUE\">" +
                "    <MY_PROPERTY>12.34</MY_PROPERTY>" +
                "  </CHILDB>" +
                "</PARENT>");
        XmlMapper xmlMapper = new XmlMapper();
        Parent deserializedParent = xmlMapper.readValue(stringWriter.toString(), Parent.class);
    }

}

class Root {

    @JacksonXmlProperty(localName = "PARENT")
    public Parent parent;

}

@JsonIgnoreProperties(ignoreUnknown = true)
class Parent {

    @JacksonXmlProperty(localName = "MY_ATTR", isAttribute = true)
    public String myAttribute;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "MY_PROPERTY")
    public List<ChildA> childrenA = new ArrayList<>();

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "CHILDB")
    public List<ChildB> childrenB = new ArrayList<>();

}

class ChildA {

}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
class ChildB {

    @JacksonXmlProperty(localName = "MY_PROPERTY")
    public Double value;

}
@JulienHoueix
Copy link
Author

Maybe related to #294

@JulienHoueix
Copy link
Author

I looked at the Jackson code.
It seems that the problem is related to JacksonXmlElementWrapper annotations with "useWrapping = false".

In class "com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser", there is the following code in the method "nextToken()" :

        // Ok: virtual wrapping can be done by simply repeating current START_ELEMENT.
        // Couple of ways to do it; but start by making _xmlTokens replay the thing...
        if (_namesToWrap != null && _namesToWrap.contains(name)) {
            _xmlTokens.repeatStartElement();
        }

where "_namesToWrap" contains the property lists that have "useWrapping = false".

The problem is that when we are parsing "<MY_PROPERTY>12.34</MY_PROPERTY>" of "CHILDB", the list "_namesToWrap" contains "MY_PROPERTY" and "CHILD_B", so it considers that "MY_PROPERTY" should be an unwrapped list instead of a Double value.

I think the problem is that the property "_namesToWrap" is not up to date in that part of the code. It works if I replace the code with the following :

        // Ok: virtual wrapping can be done by simply repeating current START_ELEMENT.
        // Couple of ways to do it; but start by making _xmlTokens replay the thing...
        _namesToWrap = _parsingContext.getNamesToWrap();
        if (_namesToWrap != null && _namesToWrap.contains(name)) {
            _xmlTokens.repeatStartElement();
        }

PS : I was willing to do a PR, but there are several tests that do not pass (EnumIssue9Test for example) when I retrieved the code, so I don't really know if it creates regressions.

@mkamalas
Copy link

@JulienHoueix - Please advise if you found a workaround for this issue.

@JulienHoueix
Copy link
Author

@JulienHoueix - Please advise if you found a workaround for this issue.

No

@DonaldMaparura
Copy link

you can use json and include your attributes in an object

@cowtowncoder
Copy link
Member

cowtowncoder commented May 21, 2020

(removed some intermediate comments)

Looking at structure, the real problem seems to be that

        @JacksonXmlProperty(localName = "MY_ATTR", isAttribute = true)
        public String myAttribute;

is in Parent class, but XML content

<PARENT>
  <CHILDB MY_ATTR='TEST_VALUE'>
    <MY_PROPERTY>12.34</MY_PROPERTY>
  </CHILDB>
</PARENT>

expects it for ChildB.

So I think this is fixed for 2.11.1 (to be released) at least, possibly earlier. Not sure which of fixes since 2.9.6 it would be (there are a few), but will mark fixed for 2.11.1

@cowtowncoder cowtowncoder changed the title Bug during XML deserialization : "com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.Double out of START_OBJECT token" Problem deserializing POJO with unwrapped List, ignorable attribute value May 21, 2020
@cowtowncoder cowtowncoder added 2.11 and removed 2.12 labels May 21, 2020
@cowtowncoder cowtowncoder modified the milestones: 2,, 2.11.1 May 21, 2020
cowtowncoder added a commit that referenced this issue May 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants