1 package com.fasterxml.jackson.databind; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.*; 7 import com.fasterxml.jackson.annotation.JsonTypeInfo.As; 8 import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; 9 import com.fasterxml.jackson.core.*; 10 import com.fasterxml.jackson.databind.DeserializationContext; 11 import com.fasterxml.jackson.databind.JsonDeserializer; 12 import com.fasterxml.jackson.databind.JsonSerializer; 13 import com.fasterxml.jackson.databind.KeyDeserializer; 14 import com.fasterxml.jackson.databind.ObjectMapper; 15 import com.fasterxml.jackson.databind.SerializerProvider; 16 import com.fasterxml.jackson.databind.annotation.*; 17 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 18 import com.fasterxml.jackson.databind.cfg.MapperConfig; 19 import com.fasterxml.jackson.databind.introspect.Annotated; 20 import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; 21 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; 22 import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase; 23 import com.fasterxml.jackson.databind.type.TypeFactory; 24 25 public class TestHandlerInstantiation extends BaseMapTest 26 { 27 /* 28 /********************************************************************** 29 /* Helper classes, beans 30 /********************************************************************** 31 */ 32 33 @JsonDeserialize(using=MyBeanDeserializer.class) 34 @JsonSerialize(using=MyBeanSerializer.class) 35 static class MyBean 36 { 37 public String value; 38 MyBean()39 public MyBean() { this(null); } MyBean(String s)40 public MyBean(String s) { value = s; } 41 } 42 43 @SuppressWarnings("serial") 44 @JsonDeserialize(keyUsing=MyKeyDeserializer.class) 45 static class MyMap extends HashMap<String,String> { } 46 47 @JsonTypeInfo(use=Id.CUSTOM, include=As.WRAPPER_ARRAY) 48 @JsonTypeIdResolver(TestCustomIdResolver.class) 49 static class TypeIdBean { 50 public int x; 51 TypeIdBean()52 public TypeIdBean() { } TypeIdBean(int x)53 public TypeIdBean(int x) { this.x = x; } 54 } 55 56 static class TypeIdBeanWrapper { 57 public TypeIdBean bean; 58 TypeIdBeanWrapper()59 public TypeIdBeanWrapper() { this(null); } TypeIdBeanWrapper(TypeIdBean b)60 public TypeIdBeanWrapper(TypeIdBean b) { bean = b; } 61 } 62 63 /* 64 /********************************************************************** 65 /* Helper classes, serializers/deserializers/resolvers 66 /********************************************************************** 67 */ 68 69 static class MyBeanDeserializer extends JsonDeserializer<MyBean> 70 { 71 public String _prefix = ""; 72 MyBeanDeserializer(String p)73 public MyBeanDeserializer(String p) { 74 _prefix = p; 75 } 76 77 @Override deserialize(JsonParser jp, DeserializationContext ctxt)78 public MyBean deserialize(JsonParser jp, DeserializationContext ctxt) 79 throws IOException, JsonProcessingException 80 { 81 return new MyBean(_prefix+jp.getText()); 82 } 83 } 84 85 static class MyKeyDeserializer extends KeyDeserializer 86 { MyKeyDeserializer()87 public MyKeyDeserializer() { } 88 89 @Override deserializeKey(String key, DeserializationContext ctxt)90 public Object deserializeKey(String key, DeserializationContext ctxt) 91 throws IOException, JsonProcessingException 92 { 93 return "KEY"; 94 } 95 } 96 97 static class MyBeanSerializer extends JsonSerializer<MyBean> 98 { 99 public String _prefix = ""; 100 MyBeanSerializer(String p)101 public MyBeanSerializer(String p) { 102 _prefix = p; 103 } 104 105 @Override serialize(MyBean value, JsonGenerator jgen, SerializerProvider provider)106 public void serialize(MyBean value, JsonGenerator jgen, SerializerProvider provider) 107 throws IOException, JsonProcessingException 108 { 109 jgen.writeString(_prefix + value.value); 110 } 111 } 112 113 // copied from "TestCustomTypeIdResolver" 114 static class TestCustomIdResolver extends TypeIdResolverBase 115 { 116 static List<JavaType> initTypes; 117 118 final String _id; 119 TestCustomIdResolver(String idForBean)120 public TestCustomIdResolver(String idForBean) { 121 _id = idForBean; 122 } 123 124 @Override getMechanism()125 public Id getMechanism() { 126 return Id.CUSTOM; 127 } 128 129 @Override idFromValue(Object value)130 public String idFromValue(Object value) 131 { 132 if (value.getClass() == TypeIdBean.class) { 133 return _id; 134 } 135 return "unknown"; 136 } 137 138 @Override idFromValueAndType(Object value, Class<?> type)139 public String idFromValueAndType(Object value, Class<?> type) { 140 return idFromValue(value); 141 } 142 143 @Override init(JavaType baseType)144 public void init(JavaType baseType) { 145 if (initTypes != null) { 146 initTypes.add(baseType); 147 } 148 } 149 150 @Override typeFromId(DatabindContext context, String id)151 public JavaType typeFromId(DatabindContext context, String id) 152 { 153 if (id.equals(_id)) { 154 return TypeFactory.defaultInstance().constructType(TypeIdBean.class); 155 } 156 return null; 157 } 158 @Override idFromBaseType()159 public String idFromBaseType() { 160 return "xxx"; 161 } 162 } 163 164 /* 165 /********************************************************************** 166 /* Helper classes, handler instantiator 167 /********************************************************************** 168 */ 169 170 static class MyInstantiator extends HandlerInstantiator 171 { 172 private final String _prefix; 173 MyInstantiator(String p)174 public MyInstantiator(String p) { 175 _prefix = p; 176 } 177 178 @Override deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> deserClass)179 public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, 180 Annotated annotated, 181 Class<?> deserClass) 182 { 183 if (deserClass == MyBeanDeserializer.class) { 184 return new MyBeanDeserializer(_prefix); 185 } 186 return null; 187 } 188 189 @Override keyDeserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> keyDeserClass)190 public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, 191 Annotated annotated, Class<?> keyDeserClass) 192 { 193 if (keyDeserClass == MyKeyDeserializer.class) { 194 return new MyKeyDeserializer(); 195 } 196 return null; 197 198 } 199 200 @Override serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass)201 public JsonSerializer<?> serializerInstance(SerializationConfig config, 202 Annotated annotated, Class<?> serClass) 203 { 204 if (serClass == MyBeanSerializer.class) { 205 return new MyBeanSerializer(_prefix); 206 } 207 return null; 208 } 209 210 @Override typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass)211 public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, 212 Annotated annotated, Class<?> resolverClass) 213 { 214 if (resolverClass == TestCustomIdResolver.class) { 215 return new TestCustomIdResolver("!!!"); 216 } 217 return null; 218 } 219 220 @Override typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, Class<?> builderClass)221 public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, 222 Class<?> builderClass) 223 { 224 return null; 225 } 226 } 227 228 /* 229 /********************************************************************** 230 /* Unit tests 231 /********************************************************************** 232 */ 233 testDeserializer()234 public void testDeserializer() throws Exception 235 { 236 ObjectMapper mapper = new ObjectMapper(); 237 mapper.setHandlerInstantiator(new MyInstantiator("abc:")); 238 MyBean result = mapper.readValue(quote("123"), MyBean.class); 239 assertEquals("abc:123", result.value); 240 } 241 testKeyDeserializer()242 public void testKeyDeserializer() throws Exception 243 { 244 ObjectMapper mapper = new ObjectMapper(); 245 mapper.setHandlerInstantiator(new MyInstantiator("abc:")); 246 MyMap map = mapper.readValue("{\"a\":\"b\"}", MyMap.class); 247 // easiest to test by just serializing... 248 assertEquals("{\"KEY\":\"b\"}", mapper.writeValueAsString(map)); 249 } 250 testSerializer()251 public void testSerializer() throws Exception 252 { 253 ObjectMapper mapper = new ObjectMapper(); 254 mapper.setHandlerInstantiator(new MyInstantiator("xyz:")); 255 assertEquals(quote("xyz:456"), mapper.writeValueAsString(new MyBean("456"))); 256 } 257 testTypeIdResolver()258 public void testTypeIdResolver() throws Exception 259 { 260 ObjectMapper mapper = new ObjectMapper(); 261 mapper.setHandlerInstantiator(new MyInstantiator("foobar")); 262 String json = mapper.writeValueAsString(new TypeIdBeanWrapper(new TypeIdBean(123))); 263 // should now use our custom id scheme: 264 assertEquals("{\"bean\":[\"!!!\",{\"x\":123}]}", json); 265 // and bring it back too: 266 TypeIdBeanWrapper result = mapper.readValue(json, TypeIdBeanWrapper.class); 267 TypeIdBean bean = result.bean; 268 assertEquals(123, bean.x); 269 } 270 271 } 272