package com.fasterxml.jackson.databind.deser; import java.util.*; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.type.TypeFactory; @SuppressWarnings("serial") public class TestGenericMapDeser extends BaseMapTest { /* /********************************************************** /* Test classes, enums /********************************************************** */ static class BooleanWrapper { final Boolean b; @JsonCreator BooleanWrapper(Boolean value) { b = value; } } static class StringWrapper { final String str; @JsonCreator StringWrapper(String value) { str = value; } } static class MapSubClass extends HashMap<String,BooleanWrapper> { } /** * Map class that should behave like {@link MapSubClass}, but by * using annotations. */ @JsonDeserialize(keyAs=StringWrapper.class, contentAs=BooleanWrapper.class) static class AnnotatedMap extends HashMap<Object,Object> { } interface MapWrapper<K,V> extends java.io.Serializable { public abstract Map<K,V> getEntries(); } static class StringMap implements MapWrapper<String,Long> { private Map<String,Long> entries = new LinkedHashMap<String,Long>(); public StringMap() { } @Override public Map<String,Long> getEntries() { return entries; } } static class StringWrapperValueMap<KEY> extends HashMap<KEY,StringWrapper> { } static class StringStringWrapperMap extends StringWrapperValueMap<String> { } static class KeyTypeCtor { protected String value; public KeyTypeCtor(String v) { value = v; } } static class KeyTypeFactory { protected String value; private KeyTypeFactory(String v, boolean foo) { value = v; } @JsonCreator public static KeyTypeFactory create(String str) { return new KeyTypeFactory(str, true); } } /* /********************************************************** /* Test methods for sub-classing /********************************************************** */ /** * Verifying that sub-classing works ok wrt generics information */ public void testMapSubClass() throws Exception { ObjectMapper mapper = new ObjectMapper(); MapSubClass result = mapper.readValue ("{\"a\":true }", MapSubClass.class); assertEquals(1, result.size()); Object value = result.get("a"); assertEquals(BooleanWrapper.class, value.getClass()); BooleanWrapper bw = (BooleanWrapper) value; assertEquals(Boolean.TRUE, bw.b); } public void testMapWrapper() throws Exception { StringMap value = new ObjectMapper().readValue ("{\"entries\":{\"a\":9} }", StringMap.class); assertNotNull(value.getEntries()); assertEquals(1, value.getEntries().size()); assertEquals(Long.valueOf(9), value.getEntries().get("a")); } public void testIntermediateTypes() throws Exception { StringStringWrapperMap result = new ObjectMapper().readValue ("{\"a\":\"b\"}", StringStringWrapperMap.class); assertEquals(1, result.size()); Object value = result.get("a"); assertNotNull(value); assertEquals(value.getClass(), StringWrapper.class); assertEquals("b", ((StringWrapper) value).str); } /* /********************************************************** /* Test methods for sub-classing for annotation handling /********************************************************** */ /** * Verifying that sub-classing works ok wrt generics information */ public void testAnnotatedMap() throws Exception { ObjectMapper mapper = new ObjectMapper(); AnnotatedMap result = mapper.readValue ("{\"a\":true }", AnnotatedMap.class); assertEquals(1, result.size()); Map.Entry<Object,Object> en = result.entrySet().iterator().next(); assertEquals(StringWrapper.class, en.getKey().getClass()); assertEquals(BooleanWrapper.class, en.getValue().getClass()); assertEquals("a", ((StringWrapper) en.getKey()).str); assertEquals(Boolean.TRUE, ((BooleanWrapper) en.getValue()).b); } /* /********************************************************** /* Test methods for ensuring @JsonCreator works for keys /********************************************************** */ public void testKeyViaCtor() throws Exception { ObjectMapper mapper = new ObjectMapper(); Map<KeyTypeCtor,Integer> map = mapper.readValue("{\"a\":123}", TypeFactory.defaultInstance().constructMapType(HashMap.class, KeyTypeCtor.class, Integer.class)); assertEquals(1, map.size()); Map.Entry<?,?> entry = map.entrySet().iterator().next(); assertEquals(Integer.valueOf(123), entry.getValue()); Object key = entry.getKey(); assertEquals(KeyTypeCtor.class, key.getClass()); assertEquals("a", ((KeyTypeCtor) key).value); } public void testKeyViaFactory() throws Exception { ObjectMapper mapper = new ObjectMapper(); Map<KeyTypeCtor,Integer> map = mapper.readValue("{\"a\":123}", TypeFactory.defaultInstance().constructMapType(HashMap.class, KeyTypeFactory.class, Integer.class)); assertEquals(1, map.size()); Map.Entry<?,?> entry = map.entrySet().iterator().next(); assertEquals(Integer.valueOf(123), entry.getValue()); Object key = entry.getKey(); assertEquals(KeyTypeFactory.class, key.getClass()); assertEquals("a", ((KeyTypeFactory) key).value); } }