- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.4k
Closed
Milestone
Description
Hi everyone!
After migration from Jackson 1.9.x to 2.x (the problem can be reproduced in 2.5.0) I've got a problem deserializing generic collections.
Here's the test that documents the behavour.
Am I doing something wrong?
package com.fasterxml.jackson.databind.test;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
/**
 * Deserialization of class with generic collection inside depends on how is was deserialized first time.
 */
public class JacksonPolymorphicDeSerFailTest {
    private static final int TIMESTAMP = 123456;
    private final MapContainer originMap =
            new MapContainer(ImmutableMap.<String, Object>of("DateValue", new Date(TIMESTAMP)));
    /**
     * If the class was first deserialized as polymorphic field,
     * deserialization will fail at complex type.
     */
    @Test
    public void testFactorsSerializationFail() throws IOException, JSONException {
        ObjectMapper mapper = new ObjectMapper();
        // incorrect
        MapContainer deserMapBad = createDeSerMapContainer(originMap, mapper);
        assertNotEquals(originMap, deserMapBad);
        assertEquals(ImmutableList.of("java.util.Date", TIMESTAMP),
                deserMapBad.getMap().get("DateValue"));
        // incorrect again
        assertNotEquals(originMap, mapper.readValue(mapper.writeValueAsString(originMap),
                MapContainer.class));
    }
    /**
     * If the class was first deserialized as is,
     * deserialization will work correctly.
     */
    @Test
    public void testFactorsSerializationMagicGood() throws IOException, JSONException {
        ObjectMapper mapper = new ObjectMapper();
        // commenting out the following statement will fail the test
        assertEquals(new MapContainer(ImmutableMap.<String, Object>of("1", 1)),
                mapper.readValue(
                        mapper.writeValueAsString(new MapContainer(ImmutableMap.<String, Object>of("1", 1))),
                        MapContainer.class));
        MapContainer deserMapGood = createDeSerMapContainer(originMap, mapper);
        // correct
        assertEquals(originMap, deserMapGood);
        assertEquals(new Date(TIMESTAMP), deserMapGood.getMap().get("DateValue"));
        // correct again
        assertEquals(originMap, mapper.readValue(mapper.writeValueAsString(originMap), MapContainer.class));
    }
    private static MapContainer createDeSerMapContainer(MapContainer originMap, ObjectMapper mapper)
            throws JSONException, IOException {
        PolymorphicValueWrapper result = new PolymorphicValueWrapper();
        result.setValue(originMap);
        String json = mapper.writeValueAsString(result);
        System.out.println("Original map json: " + json);
        JSONAssert.assertEquals("{\"value\":{\"@class\":"
                        + "\"com.fasterxml.jackson.databind.test.JacksonPolymorphicDeSerFailTest$MapContainer\","
                        + "\"map\":{\"DateValue\":[\"java.util.Date\",123456]}}}",
                new JSONObject(json), true);
        PolymorphicValueWrapper deserializedResult = mapper.readValue(json, PolymorphicValueWrapper.class);
        System.out.println("Deserialized map json: " + mapper.writeValueAsString(deserializedResult));
        return (MapContainer) deserializedResult.getValue();
    }
    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
    public static class MapContainer {
        @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,
                include = JsonTypeInfo.As.PROPERTY,
                property = "@class")
        private Map<String, Object> map;
        public MapContainer() { }
        public MapContainer(Map<String, Object> map) {
            this.map = map;
        }
        public Map<String, Object> getMap() {
            return map;
        }
        public void setMap(Map<String, Object> map) {
            this.map = map;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            MapContainer that = (MapContainer) o;
            if (map != null ? !map.equals(that.map) : that.map != null) {
                return false;
            }
            return true;
        }
        @Override
        public int hashCode() {
            return map != null ? map.hashCode() : 0;
        }
        @Override
        public String toString() {
            return "MapContainer{" +
                    "map=" + map +
                    '}';
        }
    }
    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
    public static class PolymorphicValueWrapper {
        @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,
                include = JsonTypeInfo.As.PROPERTY,
                property = "@class")
        private Object value;
        public Object getValue() {
            return value;
        }
        public void setValue(Object value) {
            this.value = value;
        }
    }
}Metadata
Metadata
Assignees
Labels
No labels