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

convertValue doesn't work on unwrapped lists where readValue works #332

Closed
rattaman123 opened this issue Feb 8, 2019 · 4 comments
Closed

Comments

@rattaman123
Copy link

Following code results in an exception. The (commented) readValue works properly while convertValue on JsonNode fails. Looks like a bug to me.

import java.util.List;
import org.junit.Test;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper    ;

public class JacksonListTest {

    public static class A {
        public String c;
        @JacksonXmlElementWrapper(useWrapping=false)
        public List<String> as;
    }

    @Test
    public void deserializeTest() throws Exception
    {
        XmlMapper mapper = new XmlMapper();
        String xml = "<A><c>c</c><as>a1</as><as>a2</as></A>";
        //mapper.readValue(xml, A.class);
        mapper.convertValue(mapper.readTree(xml), A.class);
    }

}

Exception:

Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of VALUE_STRING token
 at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: zm.study.xmlserialize.jackson.JacksonListTest$A["as"])
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1139)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1093)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.handleNonArray(StringCollectionDeserializer.java:266)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize(StringCollectionDeserializer.java:179)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize(StringCollectionDeserializer.java:169)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize(StringCollectionDeserializer.java:21)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
	at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:113)
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3745)
	... 25 more
@cowtowncoder
Copy link
Member

This should be filed at jackson-dataformat-xml as it is XML specific. Will transfer.

@cowtowncoder cowtowncoder transferred this issue from FasterXML/jackson-databind Feb 9, 2019
@rattaman123
Copy link
Author

rattaman123 commented Feb 12, 2019

So I have this issue on StackOverflow also and someone provided a partial solution:
https://stackoverflow.com/questions/54597977/cannot-deserialize-convert-unwrapped-list-when-its-second-in-class-using-jack

package zm.study.xmlserialize.jackson;

import java.util.List;

import org.junit.Test;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;

public class JacksonListTest {
    
    public static class A {
        public String c;
        @JacksonXmlElementWrapper(useWrapping=false)
        public List<String> as;
    }

    public static class B {
        public String c;
        @JacksonXmlElementWrapper(useWrapping=true)
        public List<String> as;
    }

    XmlMapper mapper = (XmlMapper)new XmlMapper().registerModule(new SimpleModule().addDeserializer(JsonNode.class, new JsonNodeDeserializer() {
        @Override
        protected void _handleDuplicateField(JsonParser p, DeserializationContext ctxt, 
                                             JsonNodeFactory nodeFactory, String fieldName, ObjectNode objectNode, 
                                             JsonNode oldValue, JsonNode newValue) throws JsonProcessingException {
            super._handleDuplicateField(p, ctxt, nodeFactory, fieldName, objectNode, oldValue, newValue);

            ArrayNode array;
            if (oldValue instanceof ArrayNode) {
                // Merge 3-rd, 4-th, ..., n-th element to already existed array
                array = (ArrayNode) oldValue;
                array.add(newValue);
            } else {
                // Merge first two elements
                array = nodeFactory.arrayNode();
                array.add(oldValue);
                array.add(newValue);
            }
            objectNode.set(fieldName, array);
        }
    }));
    		
    
    @Test
    public void deserializeUnwrappedTest() throws Exception
    {
        String xml = "<A><c>c</c><as>a1</as><as>a2</as></A>";
//        A a = mapper.readValue(xml, A.class);
        JsonNode node = mapper.readTree(xml);
        A a = mapper.convertValue(node, A.class);
        System.out.println(a.as);
    }

    @Test
    public void deserializeWrappedTest() throws Exception
    {
        String xml = "<B><c>c</c><as><as>a1</as><as>a2</as></as></B>";
//        A value = mapper.readValue(xml, A.class);
        JsonNode node = mapper.readTree(xml);
        B value = mapper.convertValue(node, B.class);
        System.out.println(value.as);
    }

}

This will preserve information in the JsonNode tree and it seems to work out of the box for the unwrapped lists but it still fails for the wrapped lists.

Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
 at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: zm.study.xmlserialize.jackson.JacksonListTest$B["as"])
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1139)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1093)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.handleNonArray(StringCollectionDeserializer.java:266)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize(StringCollectionDeserializer.java:179)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize(StringCollectionDeserializer.java:169)
	at com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize(StringCollectionDeserializer.java:21)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3745)
	... 25 more

@cowtowncoder
Copy link
Member

Basically: JsonNode DOES NOT support multiple property values, and as such its use (via readTree()) is not support for content with sequences of same element name. Only databinding supports such representation of arrays/Collections.

@cowtowncoder
Copy link
Member

Actually, #403 changes JsonNode to support multiple property values.

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