1 package com.fasterxml.jackson.databind.ser; 2 3 import java.util.*; 4 5 import com.fasterxml.jackson.annotation.*; 6 import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; 7 import com.fasterxml.jackson.databind.*; 8 import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 9 import com.fasterxml.jackson.databind.annotation.JsonSerialize; 10 11 /** 12 * Unit tests for verifying that field-backed properties can also be serialized 13 * (since version 1.1) as well as getter-accessible properties. 14 */ 15 public class FieldSerializationTest 16 extends BaseMapTest 17 { 18 /* 19 /********************************************************** 20 /* Annotated helper classes 21 /********************************************************** 22 */ 23 24 static class SimpleFieldBean 25 { 26 public int x, y; 27 28 // not auto-detectable, not public 29 int z; 30 31 // ignored, not detectable either 32 @JsonIgnore public int a; 33 } 34 35 static class SimpleFieldBean2 36 { 37 @JsonSerialize String[] values; 38 39 // note: this annotation should not matter for serialization: 40 @JsonDeserialize int dummy; 41 } 42 43 static class TransientBean 44 { 45 public int a; 46 // transients should not be included 47 public transient int b; 48 // or statics 49 public static int c; 50 } 51 52 @JsonAutoDetect(setterVisibility=Visibility.PUBLIC_ONLY, fieldVisibility=Visibility.NONE) 53 public class NoAutoDetectBean 54 { 55 // not auto-detectable any more 56 public int x; 57 58 @JsonProperty("z") 59 public int _z; 60 } 61 62 /** 63 * Let's test invalid bean too: can't have 2 logical properties 64 * with same name. 65 *<p> 66 * 21-Feb-2010, tatus: That is, not within same class. 67 * As per [JACKSON-226] it is acceptable to "override" 68 * field definitions in sub-classes. 69 */ 70 public static class DupFieldBean 71 { 72 @JsonProperty("foo") 73 public int _z; 74 75 @JsonSerialize 76 private int foo; 77 } 78 79 public static class DupFieldBean2 80 { 81 public int z; 82 83 @JsonProperty("z") 84 public int _z; 85 } 86 87 @SuppressWarnings("hiding") 88 public static class OkDupFieldBean 89 extends SimpleFieldBean 90 { 91 @JsonProperty("x") 92 protected int myX; 93 94 public int y; 95 OkDupFieldBean(int x, int y)96 public OkDupFieldBean(int x, int y) { 97 this.myX = x; 98 this.y = y; 99 } 100 } 101 102 /** 103 * It is ok to have a method-based and field-based property 104 * introspectable: only one should be serialized, and since 105 * methods have precedence, it should be the method one. 106 */ 107 public static class FieldAndMethodBean 108 { 109 @JsonProperty public int z; 110 getZ()111 @JsonProperty("z") public int getZ() { return z+1; } 112 } 113 114 @JsonInclude(JsonInclude.Include.NON_EMPTY) 115 public class Item240 { 116 @JsonProperty 117 private String id; 118 // only include annotation to ensure it won't override settings 119 @JsonSerialize(typing=JsonSerialize.Typing.STATIC) 120 private String state; 121 Item240(String id, String state)122 public Item240(String id, String state) { 123 this.id = id; 124 this.state = state; 125 } 126 } 127 128 /* 129 /********************************************************** 130 /* Main tests, success 131 /********************************************************** 132 */ 133 134 private final ObjectMapper MAPPER = newJsonMapper(); 135 testSimpleAutoDetect()136 public void testSimpleAutoDetect() throws Exception 137 { 138 SimpleFieldBean bean = new SimpleFieldBean(); 139 // let's set x, leave y as is 140 bean.x = 13; 141 Map<String,Object> result = writeAndMap(MAPPER, bean); 142 assertEquals(2, result.size()); 143 assertEquals(Integer.valueOf(13), result.get("x")); 144 assertEquals(Integer.valueOf(0), result.get("y")); 145 } 146 147 @SuppressWarnings("unchecked") testSimpleAnnotation()148 public void testSimpleAnnotation() throws Exception 149 { 150 SimpleFieldBean2 bean = new SimpleFieldBean2(); 151 bean.values = new String[] { "a", "b" }; 152 Map<String,Object> result = writeAndMap(MAPPER, bean); 153 assertEquals(1, result.size()); 154 List<String> values = (List<String>) result.get("values"); 155 assertEquals(2, values.size()); 156 assertEquals("a", values.get(0)); 157 assertEquals("b", values.get(1)); 158 } 159 testTransientAndStatic()160 public void testTransientAndStatic() throws Exception 161 { 162 TransientBean bean = new TransientBean(); 163 Map<String,Object> result = writeAndMap(MAPPER, bean); 164 assertEquals(1, result.size()); 165 assertEquals(Integer.valueOf(0), result.get("a")); 166 } 167 testNoAutoDetect()168 public void testNoAutoDetect() throws Exception 169 { 170 NoAutoDetectBean bean = new NoAutoDetectBean(); 171 bean._z = -4; 172 Map<String,Object> result = writeAndMap(MAPPER, bean); 173 assertEquals(1, result.size()); 174 assertEquals(Integer.valueOf(-4), result.get("z")); 175 } 176 177 /** 178 * Unit test that verifies that if both a field and a getter 179 * method exist for a logical property (which is allowed), 180 * getter has precendence over field. 181 */ testMethodPrecedence()182 public void testMethodPrecedence() throws Exception 183 { 184 FieldAndMethodBean bean = new FieldAndMethodBean(); 185 bean.z = 9; 186 assertEquals(10, bean.getZ()); 187 assertEquals("{\"z\":10}", MAPPER.writeValueAsString(bean)); 188 } 189 190 /** 191 * Testing [JACKSON-226]: it is ok to have "field override", 192 * as long as there are no intra-class conflicts. 193 */ testOkDupFields()194 public void testOkDupFields() throws Exception 195 { 196 OkDupFieldBean bean = new OkDupFieldBean(1, 2); 197 Map<String,Object> json = writeAndMap(MAPPER, bean); 198 assertEquals(2, json.size()); 199 assertEquals(Integer.valueOf(1), json.get("x")); 200 assertEquals(Integer.valueOf(2), json.get("y")); 201 } 202 testIssue240()203 public void testIssue240() throws Exception 204 { 205 Item240 bean = new Item240("a12", null); 206 assertEquals(MAPPER.writeValueAsString(bean), "{\"id\":\"a12\"}"); 207 } 208 209 /* 210 /********************************************************** 211 /* Main tests, failure cases 212 /********************************************************** 213 */ 214 testFailureDueToDups()215 public void testFailureDueToDups() throws Exception 216 { 217 try { 218 writeAndMap(MAPPER, new DupFieldBean()); 219 } catch (JsonMappingException e) { 220 verifyException(e, "Multiple fields representing"); 221 } 222 } 223 testFailureDueToDupField()224 public void testFailureDueToDupField() throws Exception 225 { 226 try { 227 writeAndMap(MAPPER, new DupFieldBean2()); 228 } catch (JsonMappingException e) { 229 verifyException(e, "Multiple fields representing"); 230 } 231 } 232 } 233 234