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.annotation.JsonAutoDetect.Visibility; 8 import com.fasterxml.jackson.core.JsonGenerator; 9 import com.fasterxml.jackson.databind.*; 10 import com.fasterxml.jackson.databind.annotation.JsonSerialize; 11 import com.fasterxml.jackson.databind.json.JsonMapper; 12 13 /** 14 * This unit test suite tests use of @JsonClass Annotation 15 * with bean serialization. 16 */ 17 public class TestJsonSerialize 18 extends BaseMapTest 19 { 20 /* 21 /********************************************************** 22 /* Annotated helper classes 23 /********************************************************** 24 */ 25 26 interface ValueInterface { getX()27 public int getX(); 28 } 29 30 static class ValueClass 31 implements ValueInterface 32 { 33 @Override getX()34 public int getX() { return 3; } getY()35 public int getY() { return 5; } 36 } 37 38 /** 39 * Test class to verify that <code>JsonSerialize.as</code> 40 * works as expected 41 */ 42 static class WrapperClassForAs 43 { 44 @JsonSerialize(as=ValueInterface.class) getValue()45 public ValueClass getValue() { 46 return new ValueClass(); 47 } 48 } 49 50 // This should indicate that static type be used for all fields 51 @JsonSerialize(typing=JsonSerialize.Typing.STATIC) 52 static class WrapperClassForStaticTyping 53 { getValue()54 public ValueInterface getValue() { 55 return new ValueClass(); 56 } 57 } 58 59 static class WrapperClassForStaticTyping2 60 { 61 @JsonSerialize(typing=JsonSerialize.Typing.STATIC) getStaticValue()62 public ValueInterface getStaticValue() { 63 return new ValueClass(); 64 } 65 66 @JsonSerialize(typing=JsonSerialize.Typing.DYNAMIC) getDynamicValue()67 public ValueInterface getDynamicValue() { 68 return new ValueClass(); 69 } 70 } 71 72 /** 73 * Test bean that has an invalid {@link JsonSerialize} annotation. 74 */ 75 static class BrokenClass 76 { 77 // invalid annotation: String not a supertype of Long 78 @JsonSerialize(as=String.class) getValue()79 public Long getValue() { 80 return Long.valueOf(4L); 81 } 82 } 83 84 @SuppressWarnings("serial") 85 static class ValueMap extends HashMap<String,ValueInterface> { } 86 @SuppressWarnings("serial") 87 static class ValueList extends ArrayList<ValueInterface> { } 88 @SuppressWarnings("serial") 89 static class ValueLinkedList extends LinkedList<ValueInterface> { } 90 91 // Classes for [JACKSON-294] 92 static class Foo294 93 { 94 @JsonProperty private String id; 95 @JsonSerialize(using = Bar294Serializer.class) 96 private Bar294 bar; 97 Foo294()98 public Foo294() { } Foo294(String id, String id2)99 public Foo294(String id, String id2) { 100 this.id = id; 101 bar = new Bar294(id2); 102 } 103 } 104 105 static class Bar294{ 106 @JsonProperty protected String id; 107 @JsonProperty protected String name; 108 Bar294()109 public Bar294() { } Bar294(String id)110 public Bar294(String id) { 111 this.id = id; 112 } 113 getId()114 public String getId() { return id; } getName()115 public String getName() { return name; } 116 } 117 118 static class Bar294Serializer extends JsonSerializer<Bar294> 119 { 120 @Override serialize(Bar294 bar, JsonGenerator jgen, SerializerProvider provider)121 public void serialize(Bar294 bar, JsonGenerator jgen, 122 SerializerProvider provider) throws IOException 123 { 124 jgen.writeString(bar.id); 125 } 126 } 127 128 /* 129 /********************************************************** 130 /* Main tests 131 /********************************************************** 132 */ 133 134 final ObjectMapper MAPPER = objectMapper(); 135 136 @SuppressWarnings("unchecked") testSimpleValueDefinition()137 public void testSimpleValueDefinition() throws Exception 138 { 139 Map<String,Object> result = writeAndMap(MAPPER, new WrapperClassForAs()); 140 assertEquals(1, result.size()); 141 Object ob = result.get("value"); 142 // Should see only "x", not "y" 143 result = (Map<String,Object>) ob; 144 assertEquals(1, result.size()); 145 assertEquals(Integer.valueOf(3), result.get("x")); 146 } 147 testBrokenAnnotation()148 public void testBrokenAnnotation() throws Exception 149 { 150 try { 151 serializeAsString(MAPPER, new BrokenClass()); 152 fail("Should not succeed"); 153 } catch (Exception e) { 154 verifyException(e, "types not related"); 155 } 156 } 157 158 @SuppressWarnings("unchecked") testStaticTypingForClass()159 public void testStaticTypingForClass() throws Exception 160 { 161 Map<String,Object> result = writeAndMap(MAPPER, new WrapperClassForStaticTyping()); 162 assertEquals(1, result.size()); 163 Object ob = result.get("value"); 164 // Should see only "x", not "y" 165 result = (Map<String,Object>) ob; 166 assertEquals(1, result.size()); 167 assertEquals(Integer.valueOf(3), result.get("x")); 168 } 169 170 @SuppressWarnings("unchecked") testMixedTypingForClass()171 public void testMixedTypingForClass() throws Exception 172 { 173 Map<String,Object> result = writeAndMap(MAPPER, new WrapperClassForStaticTyping2()); 174 assertEquals(2, result.size()); 175 176 Object obStatic = result.get("staticValue"); 177 // Should see only "x", not "y" 178 Map<String,Object> stat = (Map<String,Object>) obStatic; 179 assertEquals(1, stat.size()); 180 assertEquals(Integer.valueOf(3), stat.get("x")); 181 182 Object obDynamic = result.get("dynamicValue"); 183 // Should see both 184 Map<String,Object> dyn = (Map<String,Object>) obDynamic; 185 assertEquals(2, dyn.size()); 186 assertEquals(Integer.valueOf(3), dyn.get("x")); 187 assertEquals(Integer.valueOf(5), dyn.get("y")); 188 } 189 testStaticTypingWithMap()190 public void testStaticTypingWithMap() throws Exception 191 { 192 ObjectMapper m = jsonMapperBuilder() 193 .configure(MapperFeature.USE_STATIC_TYPING, true) 194 .build(); 195 ValueMap map = new ValueMap(); 196 map.put("a", new ValueClass()); 197 assertEquals("{\"a\":{\"x\":3}}", serializeAsString(m, map)); 198 } 199 testStaticTypingWithArrayList()200 public void testStaticTypingWithArrayList() throws Exception 201 { 202 ObjectMapper m = jsonMapperBuilder() 203 .configure(MapperFeature.USE_STATIC_TYPING, true) 204 .build(); 205 ValueList list = new ValueList(); 206 list.add(new ValueClass()); 207 assertEquals("[{\"x\":3}]", m.writeValueAsString(list)); 208 } 209 testStaticTypingWithLinkedList()210 public void testStaticTypingWithLinkedList() throws Exception 211 { 212 ObjectMapper m = jsonMapperBuilder() 213 .configure(MapperFeature.USE_STATIC_TYPING, true) 214 .build(); 215 ValueLinkedList list = new ValueLinkedList(); 216 list.add(new ValueClass()); 217 assertEquals("[{\"x\":3}]", serializeAsString(m, list)); 218 } 219 testStaticTypingWithArray()220 public void testStaticTypingWithArray() throws Exception 221 { 222 ObjectMapper m = jsonMapperBuilder() 223 .configure(MapperFeature.USE_STATIC_TYPING, true) 224 .build(); 225 ValueInterface[] array = new ValueInterface[] { new ValueClass() }; 226 assertEquals("[{\"x\":3}]", serializeAsString(m, array)); 227 } 228 testIssue294()229 public void testIssue294() throws Exception 230 { 231 JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build(); 232 assertEquals("{\"bar\":\"barId\",\"id\":\"fooId\"}", 233 mapper.writeValueAsString(new Foo294("fooId", "barId"))); 234 } 235 236 @JsonPropertyOrder({ "a", "something" }) 237 static class Response { 238 public String a = "x"; 239 240 @JsonProperty //does not show up isSomething()241 public boolean isSomething() { return true; } 242 } 243 testWithIsGetter()244 public void testWithIsGetter() throws Exception 245 { 246 ObjectMapper m = new ObjectMapper(); 247 m.setVisibility(PropertyAccessor.GETTER, Visibility.NONE) 248 .setVisibility(PropertyAccessor.FIELD, Visibility.ANY) 249 .setVisibility(PropertyAccessor.CREATOR, Visibility.NONE) 250 .setVisibility(PropertyAccessor.IS_GETTER, Visibility.NONE) 251 .setVisibility(PropertyAccessor.SETTER, Visibility.NONE); 252 final String JSON = m.writeValueAsString(new Response()); 253 assertEquals(aposToQuotes("{'a':'x','something':true}"), JSON); 254 } 255 } 256