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

UnrecognizedPropertyException when containing object is a Collection #76

Closed
pierre opened this issue Aug 29, 2013 · 7 comments
Closed
Milestone

Comments

@pierre
Copy link

pierre commented Aug 29, 2013

Consider the following test:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;

import org.testng.Assert;
import org.testng.annotations.Test;

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

public class TestSimpleXml {

    public static final class Value {

        @XmlElement(name = "v")
        public String v;

        public String getV() { return v; }

        public void setV(final String v) { this.v = v; }
    }

    private static final class Values extends LinkedList<Value> {

        @XmlAttribute(name = "type")
        private String type;

        @JacksonXmlElementWrapper(localName = "value", useWrapping = false)
        @JacksonXmlProperty(localName = "value")
        private List<Value> values = new ArrayList<Value>();

        private String getType() { return type; }

        private void setType(final String type) { this.type = type; }

        private List<Value> getValues() { return values; }

        private void setValues(final List<Value> values) { this.values = values; }
    }

    @Test(groups = "fast")
    public void testCollection() throws Exception {
        final Values values = new XmlMapper().readValue("<values type=\"array\">" +
                                                        "  <value><v>c</v></value>" +
                                                        "  <value><v>d</v></value>" +
                                                        "</values>",
                                                        Values.class);
        // Throws exception on 2.2.2, fails with 2.1.2
        Assert.assertEquals(values.getValues().size(), 2);
        Assert.assertEquals(values.getValues().get(0).getV(), "c");
        Assert.assertEquals(values.getValues().get(1).getV(), "d");

        // Fails with 2.1.2, see https://github.com/FasterXML/jackson-dataformat-xml/issues/47
        Assert.assertEquals(values.getType(), "array");

        // Passes with 2.1.2
        Assert.assertEquals(values.size(), 2);
        Assert.assertEquals(values.get(0).getV(), "c");
        Assert.assertEquals(values.get(1).getV(), "d");
    }
}

The test fails on 2.2.2 with the following exception:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "type" (class com.ning.billing.recurly.model.push.TestSimpleXml$Value), not marked as ignorable (one known property: "v"])
 at [Source: java.io.StringReader@a00fa7f; line: 1, column: 22] (through reference chain: com.ning.billing.recurly.model.push.Value["type"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
    at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:555)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:708)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1160)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:315)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:157)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:123)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:230)

The test passes though if I implement Iterable<Value> instead.

Are Collections handled in a specific way? Is it possible to get the 2.1.2 behavior on 2.2.2?

@cowtowncoder
Copy link
Member

Oh. I did indeed miss this one. Having 2.1 -> 2.2 regression is unusual. And I am guessing that 2.2.3 won't differ from 2.2.2? Or 2.3.0-rc1?

@cowtowncoder
Copy link
Member

Ah. The problem here is not so much XML, but the fact that a LinkedList (like any java.util.Collection) is treated as a JSON Array, and those do not have properties.

It is, however, possible to force Jackson to ignore the fact that it has a Collection to process, and make it consider it just another POJO. This is done by:

@JsonFormat(shape=JsonFormat.Shape.OBJECT)

and could help here. I'll see what else would be needed.

cowtowncoder added a commit that referenced this issue Oct 28, 2013
@pierre
Copy link
Author

pierre commented Nov 19, 2013

FYI, I did some testing with 2.3.0.

The following snippet

        final Values values = new XmlMapper().readValue("<values type=\"array\">" +
                                                        "  <value><v>c</v></value>" +
                                                        "  <value><v>d</v></value>" +
                                                        "</values>",
                                                        Values.class);

now throws the following exception:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of END_OBJECT token

Adding @JsonFormat(shape = JsonFormat.Shape.OBJECT) solves it, but the test above fails on the following assertion:

Assert.assertEquals(values.size(), 2);

@cowtowncoder
Copy link
Member

Ok. Latter sounds like something to investigate. Without shape indication such usage can not be supported because although XML could actually represent such a use case (thanks to separation of attributes and elements!), JSON can not. So Jackson databinding can not support it across formats.

But the failure to work with Shape.OBJECT is a bug, and I hope it can be fixed.

@pierre
Copy link
Author

pierre commented Nov 26, 2013

FYI, I have found a workaround with version 2.3.0:

    @JsonIgnoreProperties(ignoreUnknown = true)
    @XmlRootElement(name = "values")
    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    private static final class Values extends ArrayList<String> {

        // Cannot use @JsonAnySetter because the value passed to the setter
        // won't be fully deserialized (e.g. Map instead of POJO)
        @JsonSetter(value = "value")
        private void setHack(final String value) {
            add(value);
        }
    }

    @Test(groups = "fast", description = "See https://github.com/FasterXML/jackson-dataformat-xml/issues/76")
    public void testCollection() throws Exception {
        final Values values = new XmlMapper().readValue("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                                                        "  <values type=\"array\">\n" +
                                                        "    <value>Hi!</value>" +
                                                        "    <value>Salut!</value>" +
                                                        "  </values>",
                                                        Values.class);
        Assert.assertEquals(values.size(), 2);
        Assert.assertEquals(values.get(0), "Hi!");
        Assert.assertEquals(values.get(1), "Salut!");
    }

pierre added a commit to killbilling/recurly-java-library that referenced this issue Nov 26, 2013
Implement a workaround to Jackson errors with collections as described here:

  FasterXML/jackson-dataformat-xml#76

This closes #21 and should unblock us for #10.

Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
@cowtowncoder
Copy link
Member

Ok good to at least have a work-around! :)

@cowtowncoder cowtowncoder added this to the 2.4.0 milestone Apr 5, 2014
@cowtowncoder
Copy link
Member

Works for 2.4.0 now.

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

2 participants