• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ser;
2 
3 import java.io.IOException;
4 import java.util.*;
5 
6 import com.fasterxml.jackson.annotation.*;
7 import com.fasterxml.jackson.core.*;
8 import com.fasterxml.jackson.databind.*;
9 import com.fasterxml.jackson.databind.introspect.AnnotatedField;
10 import com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder;
11 import com.fasterxml.jackson.databind.module.SimpleModule;
12 import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
13 import com.fasterxml.jackson.databind.ser.BeanSerializer;
14 import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder;
15 import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
16 import com.fasterxml.jackson.databind.ser.std.StdSerializer;
17 import com.fasterxml.jackson.databind.type.ArrayType;
18 import com.fasterxml.jackson.databind.type.CollectionType;
19 import com.fasterxml.jackson.databind.type.MapType;
20 
21 /**
22  * Unit tests for verifying that it is possible to configure
23  * construction of {@link BeanSerializer} instances.
24  */
25 @SuppressWarnings("serial")
26 public class BeanSerializerModifierTest extends BaseMapTest
27 {
28     static class SerializerModifierModule extends SimpleModule
29     {
30         protected BeanSerializerModifier modifier;
31 
SerializerModifierModule(BeanSerializerModifier modifier)32         public SerializerModifierModule(BeanSerializerModifier modifier)
33         {
34             super("test", Version.unknownVersion());
35             this.modifier = modifier;
36         }
37 
38         @Override
setupModule(SetupContext context)39         public void setupModule(SetupContext context)
40         {
41             super.setupModule(context);
42             if (modifier != null) {
43                 context.addBeanSerializerModifier(modifier);
44             }
45         }
46     }
47 
48     @JsonPropertyOrder({"b", "a"})
49     static class Bean {
50         public String b = "b";
51         public String a = "a";
52     }
53 
54     static class RemovingModifier extends BeanSerializerModifier
55     {
56         private final String _removedProperty;
57 
RemovingModifier(String remove)58         public RemovingModifier(String remove) { _removedProperty = remove; }
59 
60         @Override
changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)61         public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
62                 List<BeanPropertyWriter> beanProperties)
63         {
64             Iterator<BeanPropertyWriter> it = beanProperties.iterator();
65             while (it.hasNext()) {
66                 BeanPropertyWriter bpw = it.next();
67                 if (bpw.getName().equals(_removedProperty)) {
68                     it.remove();
69                 }
70             }
71             return beanProperties;
72         }
73     }
74 
75     static class ReorderingModifier extends BeanSerializerModifier
76     {
77         @Override
orderProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)78         public List<BeanPropertyWriter> orderProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)
79         {
80             TreeMap<String,BeanPropertyWriter> props = new TreeMap<String,BeanPropertyWriter>();
81             for (BeanPropertyWriter bpw : beanProperties) {
82                 props.put(bpw.getName(), bpw);
83             }
84             return new ArrayList<BeanPropertyWriter>(props.values());
85         }
86     }
87 
88     static class ReplacingModifier extends BeanSerializerModifier
89     {
90         private final JsonSerializer<?> _serializer;
91 
ReplacingModifier(JsonSerializer<?> s)92         public ReplacingModifier(JsonSerializer<?> s) { _serializer = s; }
93 
94         @Override
modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer)95         public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
96                 JsonSerializer<?> serializer) {
97             return _serializer;
98         }
99     }
100 
101     static class BuilderModifier extends BeanSerializerModifier
102     {
103         private final JsonSerializer<?> _serializer;
104 
BuilderModifier(JsonSerializer<?> ser)105         public BuilderModifier(JsonSerializer<?> ser) {
106             _serializer = ser;
107         }
108 
109         @Override
updateBuilder(SerializationConfig config, BeanDescription beanDesc, BeanSerializerBuilder builder)110         public BeanSerializerBuilder updateBuilder(SerializationConfig config,
111                 BeanDescription beanDesc, BeanSerializerBuilder builder) {
112             return new BogusSerializerBuilder(builder, _serializer);
113         }
114     }
115 
116     static class BogusSerializerBuilder extends BeanSerializerBuilder
117     {
118         private final JsonSerializer<?> _serializer;
119 
BogusSerializerBuilder(BeanSerializerBuilder src, JsonSerializer<?> ser)120         public BogusSerializerBuilder(BeanSerializerBuilder src,
121                 JsonSerializer<?> ser) {
122             super(src);
123             _serializer = ser;
124         }
125 
126         @Override
build()127         public JsonSerializer<?> build() {
128             return _serializer;
129         }
130     }
131 
132     static class BogusBeanSerializer extends JsonSerializer<Object>
133     {
134         private final int _value;
135 
BogusBeanSerializer(int v)136         public BogusBeanSerializer(int v) { _value = v; }
137 
138         @Override
serialize(Object value, JsonGenerator jgen, SerializerProvider provider)139         public void serialize(Object value, JsonGenerator jgen,
140                 SerializerProvider provider) throws IOException {
141             jgen.writeNumber(_value);
142         }
143     }
144 
145     static class EmptyBean {
146         @JsonIgnore
147         public String name = "foo";
148     }
149 
150     static class EmptyBeanModifier extends BeanSerializerModifier
151     {
152         @Override
changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)153         public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
154                 BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)
155         {
156             JavaType strType = config.constructType(String.class);
157             // we need a valid BeanPropertyDefinition; this will do (just need name to match)
158             POJOPropertyBuilder prop = new POJOPropertyBuilder(config, null, true, new PropertyName("bogus"));
159             try {
160                 AnnotatedField f = new AnnotatedField(null, EmptyBean.class.getDeclaredField("name"), null);
161                 beanProperties.add(new BeanPropertyWriter(prop, f, null,
162                         strType,
163                         null, null, strType,
164                         false, null,
165                         null));
166             } catch (NoSuchFieldException e) {
167                 throw new IllegalStateException(e.getMessage());
168             }
169             return beanProperties;
170         }
171     }
172 
173     // [Issue#539]: use post-modifier
174     static class EmptyBeanModifier539 extends BeanSerializerModifier
175     {
176         @Override
changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)177         public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
178                 BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)
179         {
180             return beanProperties;
181         }
182 
183         @Override
modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer)184         public JsonSerializer<?> modifySerializer(SerializationConfig config,
185                 BeanDescription beanDesc, JsonSerializer<?> serializer) {
186             return new BogusBeanSerializer(42);
187         }
188     }
189     // [databind#120], arrays, collections, maps
190 
191     static class ArraySerializerModifier extends BeanSerializerModifier {
192         @Override
modifyArraySerializer(SerializationConfig config, ArrayType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer)193         public JsonSerializer<?> modifyArraySerializer(SerializationConfig config,
194                 ArrayType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
195             return new StdSerializer<Object>(Object.class) {
196                 @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
197                     jgen.writeNumber(123);
198                 }
199             };
200         }
201     }
202 
203     static class CollectionSerializerModifier extends BeanSerializerModifier {
204         @Override
205         public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config,
206                 CollectionType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
207             return new StdSerializer<Object>(Object.class) {
208                 @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
209                     jgen.writeNumber(123);
210                 }
211             };
212         }
213     }
214 
215     static class MapSerializerModifier extends BeanSerializerModifier {
216         @Override
217         public JsonSerializer<?> modifyMapSerializer(SerializationConfig config,
218                 MapType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
219             return new StdSerializer<Object>(Object.class) {
220                 @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
221                     jgen.writeNumber(123);
222                 }
223             };
224         }
225     }
226 
227     static class EnumSerializerModifier extends BeanSerializerModifier {
228         @Override
229         public JsonSerializer<?> modifyEnumSerializer(SerializationConfig config,
230                 JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
231             return new StdSerializer<Object>(Object.class) {
232                 @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
233                     jgen.writeNumber(123);
234                 }
235             };
236         }
237     }
238 
239     static class KeySerializerModifier extends BeanSerializerModifier {
240         @Override
241         public JsonSerializer<?> modifyKeySerializer(SerializationConfig config,
242                 JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
243             return new StdSerializer<Object>(Object.class) {
244                 @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
245                     jgen.writeFieldName("foo");
246                 }
247             };
248         }
249     }
250 
251     /*
252     /********************************************************
253     /* Unit tests: success
254     /********************************************************
255      */
256 
257     public void testPropertyRemoval() throws Exception
258     {
259         ObjectMapper mapper = new ObjectMapper();
260         mapper.registerModule(new SerializerModifierModule(new RemovingModifier("a")));
261         Bean bean = new Bean();
262         assertEquals("{\"b\":\"b\"}", mapper.writeValueAsString(bean));
263     }
264 
265     public void testPropertyReorder() throws Exception
266     {
267         ObjectMapper mapper = new ObjectMapper();
268         mapper.registerModule(new SerializerModifierModule(new ReorderingModifier()));
269         Bean bean = new Bean();
270         assertEquals("{\"a\":\"a\",\"b\":\"b\"}", mapper.writeValueAsString(bean));
271     }
272 
273     public void testBuilderReplacement() throws Exception
274     {
275         ObjectMapper mapper = new ObjectMapper();
276         mapper.registerModule(new SerializerModifierModule(new BuilderModifier(new BogusBeanSerializer(17))));
277         Bean bean = new Bean();
278         assertEquals("17", mapper.writeValueAsString(bean));
279     }
280     public void testSerializerReplacement() throws Exception
281     {
282         ObjectMapper mapper = new ObjectMapper();
283         mapper.registerModule(new SerializerModifierModule(new ReplacingModifier(new BogusBeanSerializer(123))));
284         Bean bean = new Bean();
285         assertEquals("123", mapper.writeValueAsString(bean));
286     }
287 
288     // for [JACKSON-670]
289     public void testEmptyBean() throws Exception
290     {
291         ObjectMapper mapper = new ObjectMapper();
292         mapper.registerModule(new SimpleModule("test", Version.unknownVersion()) {
293             @Override
294             public void setupModule(SetupContext context)
295             {
296                 super.setupModule(context);
297                 context.addBeanSerializerModifier(new EmptyBeanModifier());
298             }
299         });
300         String json = mapper.writeValueAsString(new EmptyBean());
301         assertEquals("{\"bogus\":\"foo\"}", json);
302     }
303 
304     public void testEmptyBean539() throws Exception
305     {
306         ObjectMapper mapper = new ObjectMapper();
307         mapper.registerModule(new SimpleModule("test", Version.unknownVersion()) {
308             @Override
309             public void setupModule(SetupContext context)
310             {
311                 super.setupModule(context);
312                 context.addBeanSerializerModifier(new EmptyBeanModifier539());
313             }
314         });
315         String json = mapper.writeValueAsString(new EmptyBean());
316         assertEquals("42", json);
317     }
318 
319     // [databind#121]
320 
321     public void testModifyArraySerializer() throws Exception
322     {
323         ObjectMapper mapper = new ObjectMapper();
324         mapper.registerModule(new SimpleModule("test")
325             .setSerializerModifier(new ArraySerializerModifier()));
326         assertEquals("123", mapper.writeValueAsString(new Integer[] { 1, 2 }));
327     }
328 
329     public void testModifyCollectionSerializer() throws Exception
330     {
331         ObjectMapper mapper = new ObjectMapper();
332         mapper.registerModule(new SimpleModule("test")
333             .setSerializerModifier(new CollectionSerializerModifier()));
334         assertEquals("123", mapper.writeValueAsString(new ArrayList<Integer>()));
335     }
336 
337     public void testModifyMapSerializer() throws Exception
338     {
339         ObjectMapper mapper = new ObjectMapper();
340         mapper.registerModule(new SimpleModule("test")
341             .setSerializerModifier(new MapSerializerModifier()));
342         assertEquals("123", mapper.writeValueAsString(new HashMap<String,String>()));
343     }
344 
345     public void testModifyEnumSerializer() throws Exception
346     {
347         ObjectMapper mapper = new ObjectMapper();
348         mapper.registerModule(new SimpleModule("test")
349             .setSerializerModifier(new EnumSerializerModifier()));
350         assertEquals("123", mapper.writeValueAsString(ABC.C));
351     }
352 
353     public void testModifyKeySerializer() throws Exception
354     {
355         ObjectMapper mapper = new ObjectMapper();
356         mapper.registerModule(new SimpleModule("test")
357             .setSerializerModifier(new KeySerializerModifier()));
358         Map<String,Integer> map = new HashMap<String,Integer>();
359         map.put("x", 3);
360         assertEquals("{\"foo\":3}", mapper.writeValueAsString(map));
361     }
362 }
363