1 package com.fasterxml.jackson.databind.deser; 2 3 import java.io.*; 4 import java.util.*; 5 6 import com.fasterxml.jackson.core.*; 7 8 import com.fasterxml.jackson.databind.*; 9 import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 10 import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 11 12 /** 13 * Unit test suite that tests "usingXxx" properties of 14 * {@link JsonDeserialize} annotation. 15 */ 16 @SuppressWarnings("serial") 17 public class TestAnnotationUsing 18 extends BaseMapTest 19 { 20 /* 21 /********************************************************************** 22 /* Annotated Bean classes 23 /********************************************************************** 24 */ 25 26 /** 27 * Class for testing {@link JsonDeserializer} annotation 28 * for class itself. 29 */ 30 @JsonDeserialize(using=ValueDeserializer.class) 31 final static class ValueClass { 32 int _a; 33 34 /* we'll test it by not having default no-arg ctor, and leaving 35 * out single-int-arg ctor (because deserializer would use that too) 36 */ ValueClass(int a, int b)37 public ValueClass(int a, int b) { 38 _a = a; 39 } 40 } 41 42 /** 43 * Class for testing {@link JsonDeserializer} annotation 44 * for a method 45 */ 46 final static class MethodBean { 47 int[] _ints; 48 49 /* Note: could be made to work otherwise, except that 50 * to trigger failure (in absence of annotation) Json 51 * is of type VALUE_NUMBER_INT, not an Array: array would 52 * work by default, but scalar not 53 */ 54 @JsonDeserialize(using=IntsDeserializer.class) setInts(int[] i)55 public void setInts(int[] i) { 56 _ints = i; 57 } 58 } 59 60 static class ArrayBean { 61 @JsonDeserialize(contentUsing=ValueDeserializer.class) 62 public Object[] values; 63 } 64 65 static class ListBean { 66 @JsonDeserialize(contentUsing=ValueDeserializer.class) 67 public List<Object> values; 68 } 69 70 static class MapBean { 71 @JsonDeserialize(contentUsing=ValueDeserializer.class) 72 public Map<String,Object> values; 73 } 74 75 static class MapKeyBean { 76 @JsonDeserialize(keyUsing=MapKeyDeserializer.class) 77 public Map<Object,Object> values; 78 } 79 80 @JsonDeserialize(keyUsing=MapKeyDeserializer.class, contentUsing=ValueDeserializer.class) 81 static class MapKeyMap extends HashMap<Object,Object> { } 82 83 /* 84 /********************************************************************** 85 /* Deserializers 86 /********************************************************************** 87 */ 88 89 static class ValueDeserializer extends StdDeserializer<ValueClass> 90 { ValueDeserializer()91 public ValueDeserializer() { super(ValueClass.class); } 92 @Override deserialize(JsonParser jp, DeserializationContext ctxt)93 public ValueClass deserialize(JsonParser jp, DeserializationContext ctxt) 94 throws IOException, JsonProcessingException 95 { 96 int i = jp.getIntValue(); 97 return new ValueClass(i, i); 98 } 99 } 100 101 private final static class IntsDeserializer extends StdDeserializer<int[]> 102 { IntsDeserializer()103 public IntsDeserializer() { super(int[].class); } 104 @Override deserialize(JsonParser jp, DeserializationContext ctxt)105 public int[] deserialize(JsonParser jp, DeserializationContext ctxt) 106 throws IOException, JsonProcessingException 107 { 108 return new int[] { jp.getIntValue() }; 109 } 110 } 111 112 private final static class MapKeyDeserializer extends KeyDeserializer 113 { 114 @Override deserializeKey(String key, DeserializationContext ctxt)115 public Object deserializeKey(String key, DeserializationContext ctxt) 116 { 117 return new String[] { key }; 118 } 119 } 120 121 /* 122 /********************************************************************** 123 /* Tests: specifying deserializer of value itself 124 /********************************************************************** 125 */ 126 127 // Unit test to verify that {@link JsonDeserialize#using} annotation works 128 // when applied to a class testClassDeserializer()129 public void testClassDeserializer() throws Exception 130 { 131 ObjectMapper m = new ObjectMapper(); 132 ValueClass result = m.readValue(" 123 ", ValueClass.class); 133 assertEquals(123, result._a); 134 } 135 136 // Unit test to verify that {@link JsonDeserialize#using} annotation works 137 // when applied to a Method testMethodDeserializer()138 public void testMethodDeserializer() throws Exception 139 { 140 ObjectMapper m = new ObjectMapper(); 141 // note: since it's part of method, must parse from Object struct 142 MethodBean result = m.readValue(" { \"ints\" : 3 } ", MethodBean.class); 143 assertNotNull(result); 144 int[] ints = result._ints; 145 assertNotNull(ints); 146 assertEquals(1, ints.length); 147 assertEquals(3, ints[0]); 148 } 149 150 /* 151 /********************************************************************** 152 /* Tests: specifying deserializer for keys and/or contents 153 /********************************************************************** 154 */ 155 testArrayContentUsing()156 public void testArrayContentUsing() throws Exception 157 { 158 ObjectMapper m = new ObjectMapper(); 159 ArrayBean result = m.readValue(" { \"values\" : [ 1, 2, 3 ] } ", ArrayBean.class); 160 assertNotNull(result); 161 Object[] obs = result.values; 162 assertNotNull(obs); 163 assertEquals(3, obs.length); 164 assertEquals(ValueClass.class, obs[0].getClass()); 165 assertEquals(1, ((ValueClass) obs[0])._a); 166 assertEquals(ValueClass.class, obs[1].getClass()); 167 assertEquals(2, ((ValueClass) obs[1])._a); 168 assertEquals(ValueClass.class, obs[2].getClass()); 169 assertEquals(3, ((ValueClass) obs[2])._a); 170 } 171 testListContentUsing()172 public void testListContentUsing() throws Exception 173 { 174 ObjectMapper m = new ObjectMapper(); 175 ListBean result = m.readValue(" { \"values\" : [ 1, 2, 3 ] } ", ListBean.class); 176 assertNotNull(result); 177 List<Object> obs = result.values; 178 assertNotNull(obs); 179 assertEquals(3, obs.size()); 180 assertEquals(ValueClass.class, obs.get(0).getClass()); 181 assertEquals(1, ((ValueClass) obs.get(0))._a); 182 assertEquals(ValueClass.class, obs.get(1).getClass()); 183 assertEquals(2, ((ValueClass) obs.get(1))._a); 184 assertEquals(ValueClass.class, obs.get(2).getClass()); 185 assertEquals(3, ((ValueClass) obs.get(2))._a); 186 } 187 testMapContentUsing()188 public void testMapContentUsing() throws Exception 189 { 190 ObjectMapper m = new ObjectMapper(); 191 MapBean result = m.readValue(" { \"values\" : { \"a\": 1, \"b\":2 } } ", MapBean.class); 192 assertNotNull(result); 193 Map<String,Object> map = result.values; 194 assertNotNull(map); 195 assertEquals(2, map.size()); 196 assertEquals(ValueClass.class, map.get("a").getClass()); 197 assertEquals(1, ((ValueClass) map.get("a"))._a); 198 assertEquals(ValueClass.class, map.get("b").getClass()); 199 assertEquals(2, ((ValueClass) map.get("b"))._a); 200 } 201 testMapKeyUsing()202 public void testMapKeyUsing() throws Exception 203 { 204 ObjectMapper m = new ObjectMapper(); 205 MapKeyBean result = m.readValue(" { \"values\" : { \"a\": true } } ", MapKeyBean.class); 206 assertNotNull(result); 207 Map<Object,Object> map = result.values; 208 assertNotNull(map); 209 assertEquals(1, map.size()); 210 Map.Entry<Object,Object> en = map.entrySet().iterator().next(); 211 assertEquals(String[].class, en.getKey().getClass()); 212 assertEquals(Boolean.TRUE, en.getValue()); 213 } 214 215 // @since 1.8 testRootValueWithCustomKey()216 public void testRootValueWithCustomKey() throws Exception 217 { 218 ObjectMapper m = new ObjectMapper(); 219 MapKeyMap result = m.readValue(" { \"a\": 13 } ", MapKeyMap.class); 220 assertNotNull(result); 221 assertNotNull(result); 222 assertEquals(1, result.size()); 223 Map.Entry<Object,Object> en = result.entrySet().iterator().next(); 224 assertEquals(ValueClass.class, en.getValue().getClass()); 225 assertEquals(13, ((ValueClass) en.getValue())._a); 226 assertEquals(String[].class, en.getKey().getClass()); 227 } 228 229 } 230