package com.fasterxml.jackson.databind.jsontype; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.databind.*; import java.io.IOException; import java.util.*; /** * Reproduction of [https://github.com/FasterXML/jackson-databind/issues/676] *

* Deserialization of class with generic collection inside * depends on how is was deserialized first time. */ public class TestPolymorphicDeserialization676 extends BaseMapTest { private static final int TIMESTAMP = 123456; @JsonInclude(JsonInclude.Include.NON_NULL) public static class MapContainer { @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") public Map map; public MapContainer() { } public MapContainer(Map map) { this.map = map; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof MapContainer)) return false; return map.equals(((MapContainer) o).map); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[MapContainer:"); for (Map.Entry entry : map.entrySet()) { sb.append(" '").append(entry.getKey()).append("' : "); Object value = entry.getValue(); if (value == null) { sb.append("null"); } else { sb.append("(").append(value.getClass().getName()).append(") "); sb.append(String.valueOf(value)); } } return sb.append(']').toString(); } } @JsonInclude(JsonInclude.Include.NON_NULL) public static class PolymorphicValueWrapper { @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") public Object value; } private final MapContainer originMap; public TestPolymorphicDeserialization676() { Map localMap = new LinkedHashMap(); localMap.put("DateValue", new Date(TIMESTAMP)); originMap = new MapContainer(localMap); } /** * If the class was first deserialized as polymorphic field, * deserialization will fail at complex type. */ public void testDeSerFail() throws IOException { ObjectMapper mapper = new ObjectMapper(); MapContainer deserMapBad = createDeSerMapContainer(originMap, mapper); assertEquals(originMap, deserMapBad); assertEquals(originMap, mapper.readValue(mapper.writeValueAsString(originMap), MapContainer.class)); } public void testDeSerCorrect() throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS); Map map = new HashMap(); map.put("1", 1); // commenting out the following statement will fail the test assertEquals(new MapContainer(map), mapper.readValue(mapper.writeValueAsString(new MapContainer(map)), MapContainer.class)); MapContainer deserMapGood = createDeSerMapContainer(originMap, mapper); assertEquals(originMap, deserMapGood); assertEquals(new Date(TIMESTAMP), deserMapGood.map.get("DateValue")); assertEquals(originMap, mapper.readValue(mapper.writeValueAsString(originMap), MapContainer.class)); } private MapContainer createDeSerMapContainer(MapContainer src, ObjectMapper mapper) throws IOException { PolymorphicValueWrapper result = new PolymorphicValueWrapper(); result.value = src; String json = mapper.writeValueAsString(result); assertEquals("{\"value\":{\"@class\":" + "\""+getClass().getName()+"$MapContainer\"," + "\"map\":{\"DateValue\":[\"java.util.Date\",123456]}}}", json); PolymorphicValueWrapper deserializedResult = mapper.readValue(json, PolymorphicValueWrapper.class); return (MapContainer) deserializedResult.value; } }