1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.http.converter.json;
18
19 import java.io.IOException;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 import com.fasterxml.jackson.annotation.JsonTypeInfo;
25 import com.fasterxml.jackson.core.JsonGenerator;
26 import com.fasterxml.jackson.core.JsonParser;
27 import com.fasterxml.jackson.core.JsonProcessingException;
28 import com.fasterxml.jackson.core.ObjectCodec;
29 import com.fasterxml.jackson.databind.DatabindContext;
30 import com.fasterxml.jackson.databind.DeserializationConfig;
31 import com.fasterxml.jackson.databind.DeserializationContext;
32 import com.fasterxml.jackson.databind.JavaType;
33 import com.fasterxml.jackson.databind.JsonDeserializer;
34 import com.fasterxml.jackson.databind.JsonNode;
35 import com.fasterxml.jackson.databind.JsonSerializer;
36 import com.fasterxml.jackson.databind.KeyDeserializer;
37 import com.fasterxml.jackson.databind.ObjectMapper;
38 import com.fasterxml.jackson.databind.SerializationConfig;
39 import com.fasterxml.jackson.databind.SerializerProvider;
40 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
41 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
42 import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
43 import com.fasterxml.jackson.databind.annotation.JsonTypeResolver;
44 import com.fasterxml.jackson.databind.jsontype.NamedType;
45 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
46 import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
47 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
48 import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder;
49 import com.fasterxml.jackson.databind.type.TypeFactory;
50 import org.junit.Before;
51 import org.junit.Test;
52
53 import org.springframework.beans.factory.annotation.Autowired;
54 import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
55 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
56 import org.springframework.beans.factory.support.RootBeanDefinition;
57
58 import static org.junit.Assert.*;
59
60
61
62
63
64
65 public class SpringHandlerInstantiatorTests {
66
67 private SpringHandlerInstantiator instantiator;
68
69 private ObjectMapper objectMapper;
70
71
72 @Before
73 public void setup() {
74 DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
75 AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
76 bpp.setBeanFactory(bf);
77 bf.addBeanPostProcessor(bpp);
78 bf.registerBeanDefinition("capitalizer", new RootBeanDefinition(Capitalizer.class));
79 instantiator = new SpringHandlerInstantiator(bf);
80 objectMapper = Jackson2ObjectMapperBuilder.json().handlerInstantiator(instantiator).build();
81 }
82
83
84 @Test
85 public void autowiredSerializer() throws JsonProcessingException {
86 User user = new User("bob");
87 String json = this.objectMapper.writeValueAsString(user);
88 assertEquals("{\"username\":\"BOB\"}", json);
89
90 }
91
92 @Test
93 public void autowiredDeserializer() throws IOException {
94 String json = "{\"username\":\"bob\"}";
95 User user = this.objectMapper.readValue(json, User.class);
96 assertEquals(user.getUsername(), "BOB");
97 }
98
99 @Test
100 public void autowiredKeyDeserializer() throws IOException {
101 String json = "{\"credentials\":{\"bob\":\"admin\"}}";
102 SecurityRegistry registry = this.objectMapper.readValue(json, SecurityRegistry.class);
103 assertTrue(registry.getCredentials().keySet().contains("BOB"));
104 assertFalse(registry.getCredentials().keySet().contains("bob"));
105 }
106
107 @Test
108 public void applicationContextAwaretypeResolverBuilder() throws JsonProcessingException {
109 this.objectMapper.writeValueAsString(new Group("authors"));
110 assertTrue(CustomTypeResolverBuilder.isAutowiredFiledInitialized);
111 }
112
113 @Test
114 public void applicationContextAwareTypeIdResolver() throws JsonProcessingException {
115 this.objectMapper.writeValueAsString(new Group("authors"));
116 assertTrue(CustomTypeIdResolver.isAutowiredFiledInitialized);
117 }
118
119
120 public static class UserDeserializer extends JsonDeserializer<User> {
121
122 @Autowired
123 private Capitalizer capitalizer;
124
125 @Override
126 public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
127 ObjectCodec oc = jsonParser.getCodec();
128 JsonNode node = oc.readTree(jsonParser);
129 return new User(this.capitalizer.capitalize(node.get("username").asText()));
130 }
131 }
132
133
134 public static class UserSerializer extends JsonSerializer<User> {
135
136 @Autowired
137 private Capitalizer capitalizer;
138
139 @Override
140 public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
141 jsonGenerator.writeStartObject();
142 jsonGenerator.writeStringField("username", this.capitalizer.capitalize(user.getUsername()));
143 jsonGenerator.writeEndObject();
144 }
145 }
146
147
148 public static class UpperCaseKeyDeserializer extends KeyDeserializer {
149
150 @Autowired
151 private Capitalizer capitalizer;
152
153 @Override
154 public Object deserializeKey(String key, DeserializationContext context) throws IOException, JsonProcessingException {
155 return this.capitalizer.capitalize(key);
156 }
157 }
158
159
160 public static class CustomTypeResolverBuilder extends StdTypeResolverBuilder {
161
162 @Autowired
163 private Capitalizer capitalizer;
164
165 public static boolean isAutowiredFiledInitialized = false;
166
167 @Override
168 public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
169 isAutowiredFiledInitialized = (this.capitalizer != null);
170 return super.buildTypeSerializer(config, baseType, subtypes);
171 }
172
173 @Override
174 public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
175 return super.buildTypeDeserializer(config, baseType, subtypes);
176 }
177 }
178
179
180 public static class CustomTypeIdResolver implements TypeIdResolver {
181
182 @Autowired
183 private Capitalizer capitalizer;
184
185 public static boolean isAutowiredFiledInitialized = false;
186
187 public CustomTypeIdResolver() {
188 }
189
190 @Override
191 public String idFromValueAndType(Object o, Class<?> type) {
192 return type.getClass().getName();
193 }
194
195 @Override
196 public JsonTypeInfo.Id getMechanism() {
197 return JsonTypeInfo.Id.CUSTOM;
198 }
199
200 @Override
201 public JavaType typeFromId(String s) {
202 return TypeFactory.defaultInstance().constructFromCanonical(s);
203 }
204
205 @Override
206 public String idFromValue(Object value) {
207 isAutowiredFiledInitialized = (this.capitalizer != null);
208 return value.getClass().getName();
209 }
210
211 @Override
212 public void init(JavaType type) {
213 }
214
215 @Override
216 public String idFromBaseType() {
217 return null;
218 }
219
220
221 public JavaType typeFromId(DatabindContext context, String id) {
222 return null;
223 }
224 }
225
226
227 @JsonDeserialize(using = UserDeserializer.class)
228 @JsonSerialize(using = UserSerializer.class)
229 public static class User {
230
231 private String username;
232
233 public User() {
234 }
235
236 public User(String username) {
237 this.username = username;
238 }
239
240 public String getUsername() { return this.username; }
241 }
242
243
244 public static class SecurityRegistry {
245
246 @JsonDeserialize(keyUsing = UpperCaseKeyDeserializer.class)
247 private Map<String, String> credentials = new HashMap<>();
248
249 public void addCredential(String username, String credential) {
250 this.credentials.put(username, credential);
251 }
252
253 public Map<String, String> getCredentials() {
254 return credentials;
255 }
256 }
257
258
259 @JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type")
260 @JsonTypeResolver(CustomTypeResolverBuilder.class)
261 @JsonTypeIdResolver(CustomTypeIdResolver.class)
262 public static class Group {
263
264 private String name;
265
266 public Group(String name) {
267 this.name = name;
268 }
269
270 public Group() {
271 }
272
273 public String getType() {
274 return Group.class.getName();
275 }
276 }
277
278
279 public static class Capitalizer {
280
281 public String capitalize(String text) {
282 return text.toUpperCase();
283 }
284 }
285
286 }