• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ser;
2 
3 import java.io.*;
4 import java.util.*;
5 
6 
7 import com.fasterxml.jackson.annotation.*;
8 import com.fasterxml.jackson.core.*;
9 
10 import com.fasterxml.jackson.databind.*;
11 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
12 
13 /**
14  * This unit test suite tests use of Annotations for
15  * bean serialization.
16  */
17 public class TestAnnotations
18     extends BaseMapTest
19 {
20     /*
21     /**********************************************************
22     /* Helper classes
23     /**********************************************************
24      */
25 
26     /// Class for testing {@link JsonProperty} annotations with getters
27     final static class SizeClassGetter
28     {
size()29         @JsonProperty public int size() { return 3; }
foobar()30         @JsonProperty("length") public int foobar() { return -17; }
31         // note: need not be public since there's annotation
value()32         @JsonProperty protected int value() { return 0; }
33 
34         // dummy method; not a getter signature
getNotReally(int arg)35         protected int getNotReally(int arg) { return 0; }
36     }
37 
38     // And additional testing to cover [JACKSON-64]
39     final static class SizeClassGetter2
40     {
41         // Should still be considered property "x"
getX()42         @JsonProperty protected int getX() { return 3; }
43     }
44 
45     // and some support for testing [JACKSON-120]
46     final static class SizeClassGetter3
47     {
48         // Should be considered property "y" even tho non-public
getY()49         @JsonSerialize protected int getY() { return 8; }
50     }
51 
52 
53     /**
54      * Class for testing {@link JsonSerializer} annotation
55      * for class itself.
56      */
57     @JsonSerialize(using=BogusSerializer.class)
58     final static class ClassSerializer {
59     }
60 
61     /**
62      * Class for testing an active {@link JsonSerialize#using} annotation
63      * for a method
64      */
65     final static class ClassMethodSerializer {
66         private int _x;
67 
ClassMethodSerializer(int x)68         public ClassMethodSerializer(int x) { _x = x; }
69 
70         @JsonSerialize(using=StringSerializer.class)
getX()71         public int getX() { return _x; }
72     }
73 
74     /**
75      * Class for testing an inactive (one that will not have any effect)
76      * {@link JsonSerialize} annotation for a method
77      */
78     final static class InactiveClassMethodSerializer {
79         private int _x;
80 
InactiveClassMethodSerializer(int x)81         public InactiveClassMethodSerializer(int x) { _x = x; }
82 
83         // Basically, has no effect, hence gets serialized as number
84         @JsonSerialize(using=JsonSerializer.None.class)
getX()85         public int getX() { return _x; }
86     }
87 
88     /**
89      * Class for verifying that getter information is inherited
90      * as expected via normal class inheritance
91      */
92     static class BaseBean {
getX()93         public int getX() { return 1; }
94         @JsonProperty("y")
getY()95         private int getY() { return 2; }
96     }
97 
98     static class SubClassBean extends BaseBean {
getZ()99         public int getZ() { return 3; }
100     }
101 
102     // For [JACKSON-666] ("SerializationFeature of the Beast!")
103     @JsonPropertyOrder(alphabetic=true)
104     static class GettersWithoutSetters
105     {
106         public int d = 0;
107 
108         @JsonCreator
GettersWithoutSetters(@sonProperty"a") int a)109         public GettersWithoutSetters(@JsonProperty("a") int a) { }
110 
111         // included, since there is a constructor property
getA()112         public int getA() { return 3; }
113 
114         // not included, as there's nothing matching
getB()115         public int getB() { return 4; }
116 
117         // include as there is setter
getC()118         public int getC() { return 5; }
setC(int v)119         public void setC(int v) { }
120 
121         // and included, as there is a field
getD()122         public int getD() { return 6; }
123     }
124 
125     // [JACKSON-806]: override 'need-setter' with explicit annotation
126     static class GettersWithoutSetters2
127     {
128         @JsonProperty
getA()129         public int getA() { return 123; }
130     }
131 
132     /*
133     /**********************************************************
134     /* Other helper classes
135     /**********************************************************
136      */
137 
138     public final static class BogusSerializer extends JsonSerializer<Object>
139     {
140         @Override
serialize(Object value, JsonGenerator jgen, SerializerProvider provider)141         public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
142             throws IOException, JsonGenerationException
143         {
144             jgen.writeBoolean(true);
145         }
146     }
147 
148     private final static class StringSerializer extends JsonSerializer<Object>
149     {
150         @Override
serialize(Object value, JsonGenerator jgen, SerializerProvider provider)151         public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
152             throws IOException, JsonGenerationException
153         {
154             jgen.writeString("X"+value+"X");
155         }
156 
157     }
158 
159     /*
160     /**********************************************************
161     /* Main tests
162     /**********************************************************
163      */
164 
165     private final ObjectMapper MAPPER = new ObjectMapper();
166 
testSimpleGetter()167     public void testSimpleGetter() throws Exception
168     {
169         Map<String,Object> result = writeAndMap(MAPPER, new SizeClassGetter());
170         assertEquals(3, result.size());
171         assertEquals(Integer.valueOf(3), result.get("size"));
172         assertEquals(Integer.valueOf(-17), result.get("length"));
173         assertEquals(Integer.valueOf(0), result.get("value"));
174     }
175 
testSimpleGetter2()176     public void testSimpleGetter2() throws Exception
177     {
178         Map<String,Object> result = writeAndMap(MAPPER, new SizeClassGetter2());
179         assertEquals(1, result.size());
180         assertEquals(Integer.valueOf(3), result.get("x"));
181     }
182 
183     // testing [JACKSON-120], implied getter
testSimpleGetter3()184     public void testSimpleGetter3() throws Exception
185     {
186         Map<String,Object> result = writeAndMap(MAPPER, new SizeClassGetter3());
187         assertEquals(1, result.size());
188         assertEquals(Integer.valueOf(8), result.get("y"));
189     }
190 
191     /**
192      * Let's also verify that inherited super-class getters are used
193      * as expected
194      */
testGetterInheritance()195     public void testGetterInheritance() throws Exception
196     {
197         Map<String,Object> result = writeAndMap(MAPPER, new SubClassBean());
198         assertEquals(3, result.size());
199         assertEquals(Integer.valueOf(1), result.get("x"));
200         assertEquals(Integer.valueOf(2), result.get("y"));
201         assertEquals(Integer.valueOf(3), result.get("z"));
202     }
203 
204     /**
205      * Unit test to verify that {@link JsonSerialize#using} annotation works
206      * when applied to a class
207      */
testClassSerializer()208     public void testClassSerializer() throws Exception
209     {
210         StringWriter sw = new StringWriter();
211         MAPPER.writeValue(sw, new ClassSerializer());
212         assertEquals("true", sw.toString());
213     }
214 
215     /**
216      * Unit test to verify that @JsonSerializer annotation works
217      * when applied to a Method
218      */
testActiveMethodSerializer()219     public void testActiveMethodSerializer() throws Exception
220     {
221         StringWriter sw = new StringWriter();
222         MAPPER.writeValue(sw, new ClassMethodSerializer(13));
223         /* Here we will get wrapped as an object, since we have
224          * full object, just override a single property
225          */
226         assertEquals("{\"x\":\"X13X\"}", sw.toString());
227     }
228 
testInactiveMethodSerializer()229     public void testInactiveMethodSerializer() throws Exception
230     {
231         String json = MAPPER.writeValueAsString(new InactiveClassMethodSerializer(8));
232         // Here we will get wrapped as an object, since we have
233         // full object, just override a single property
234         assertEquals("{\"x\":8}", json);
235     }
236 
testGettersWithoutSetters()237     public void testGettersWithoutSetters() throws Exception
238     {
239         ObjectMapper m = new ObjectMapper();
240         GettersWithoutSetters bean = new GettersWithoutSetters(123);
241         assertFalse(m.isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS));
242 
243         // by default, all 4 found:
244         assertEquals("{\"a\":3,\"b\":4,\"c\":5,\"d\":6}", m.writeValueAsString(bean));
245 
246         // but 3 if we require mutator:
247         m = jsonMapperBuilder()
248                 .enable(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS)
249                 .build();
250         assertEquals("{\"a\":3,\"c\":5,\"d\":6}", m.writeValueAsString(bean));
251     }
252 
testGettersWithoutSettersOverride()253     public void testGettersWithoutSettersOverride() throws Exception
254     {
255         GettersWithoutSetters2 bean = new GettersWithoutSetters2();
256         ObjectMapper m = jsonMapperBuilder()
257                 .enable(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS)
258                 .build();
259         assertEquals("{\"a\":123}", m.writeValueAsString(bean));
260     }
261 }
262