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

Deserialization fails with XmlMapper and DeserializationFeature.UNWRAP_ROOT_VALUE #374

Closed
dewarim opened this issue Dec 6, 2019 · 7 comments
Milestone

Comments

@dewarim
Copy link

dewarim commented Dec 6, 2019

Simple Test case: https://github.com/dewarim/jackson-xml-debug

Using jackson-dataformat-xml version 2.10.1 @ Java 11

Given: a POJO:

@JacksonXmlRootElement(localName = "Root")
@JsonRootName("Root")
public class Root {

    @JsonProperty("id")
    String id;

    public Root(String id) {
        this.id = id;
    }

    public Root() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Root root = (Root) o;
        return Objects.equals(id, root.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

When trying to do

        ObjectMapper mapper = new XmlMapper();
       mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
        Root deserializedRoot = mapper.readValue(value, Root.class);

I get:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Root name 'id' does not match expected ('Root') for type [simple type, class test.debug.Root]
at [Source: (StringReader); line: 1, column: 7] (through reference chain: test.debug.Root["id"])

@cowtowncoder
Copy link
Member

cowtowncoder commented Dec 6, 2019

For sake of completeness (and since example above is missing a key piece, XML document), test itself is:

    @Test
    public void xml() throws JsonProcessingException {
        ObjectMapper mapper = new XmlMapper();
        mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
        String value = mapper.writeValueAsString(root);
        assertEquals("<Root><id>hello</id></Root>", value);
        Root deserializedRoot = mapper.readValue(value, Root.class);
        assertEquals(root, deserializedRoot);
    }

which actually does not look right, wrt expected XML. I am not sure if root-wrapping/unwrapping is actually expected to work with XML -- partly since the reason it exists is mostly/only to allow for working around issues CAUSED by some frameworks that add extra wrapping on JSON output.
But it seems reasonable to see if it could be supported.
If it is, however, it would mean one extra level of wrapping on writing: so you should see something more like

<Root>
  <Root>
    <id>hello</id>
  </Root>
</Root>

Another possibility, for retaining at least symmetry, would be to not add wrapping, but also not to try to unwrap (regardless of setting) on reading side.

@cowtowncoder
Copy link
Member

cowtowncoder commented Dec 7, 2019

I think I am actually inclined to work on changing things in 2.11 so that both WRAP_ROOT_VALUE and UNWRAP_ROOT_VALUE are ignored for XML backend: currently only former is.

Expectation of root wrapping (or not) is handled quite differently on ser, deser:

  1. On serialization, it is under control of SerializerProvider: XmlSerializerProvider overrides methods to essentially ignore setting already. So that's fine
  2. On deserialization, there is method useRootWrapping() in DeserializationConfig. Either that needs to be overridden (tricky), or DeserializationFeature.UNWRAP_ROOT_VALUE forced false (easyish, maybe)... but there'd still be "root name" definition to worry.

So, wrt (2), maybe should handle this from calling side. For ObjectMapper, could refactor things to make it overridable, but that would leave ObjectReader problematic. So... back to The Old Drawing Board.

cowtowncoder added a commit that referenced this issue Dec 7, 2019
@cowtowncoder cowtowncoder added this to the 2.12.0 milestone Jul 2, 2020
@cowtowncoder
Copy link
Member

Where there's will there's a way. So returning to this issue now; fix imminent.

@cowtowncoder cowtowncoder changed the title Deserialization fails with XmlMapper and UNWRAP_ROOT_VALUE Deserialization fails with XmlMapper and DeserializationFeature.UNWRAP_ROOT_VALUE Jul 2, 2020
@ionel-sirbu-crunch
Copy link

ionel-sirbu-crunch commented Jul 9, 2021

Hi @cowtowncoder, what is the fix after all? Can we still achieve root element unwrapping? If so, how?
I've just switched to v. 2.12.3 and unit tests started failing because this no longer works.

@cowtowncoder
Copy link
Member

@ionel-sirbu-crunch Unwrapping in XML has different semantics than with JSON so that feature does nothing with XML. Fix is to prevent attempts for unwrapping since that will not work the way databind would try to apply it.

For your specific problem, please file a new issue with reproduction (showing what specifically you think is failing) and include information on versions where things appeared to work.

@ionel-sirbu-crunch
Copy link

@ionel-sirbu-crunch Unwrapping in XML has different semantics than with JSON so that feature does nothing with XML. Fix is to prevent attempts for unwrapping since that will not work the way databind would try to apply it.

For your specific problem, please file a new issue with reproduction (showing what specifically you think is failing) and include information on versions where things appeared to work.

Created #485 for that matter. Thank you!

@cowtowncoder
Copy link
Member

Note: as per #485 the behavior WILL CHANGE for 2.13.0 so that:

  • Deserializer WILL AGAIN unwrap root element, but
  • Serializer STILL DOES NOT add wrapping

Second issue may be addressed with a later version (2.14 or later) but first we will want to get back to 2.11 baseline compatibility.

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

3 participants