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