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