1 package com.buckosoft.PicMan.service.support;
2
3 import java.io.IOException;
4 import java.lang.reflect.InvocationTargetException;
5 import java.util.HashSet;
6 import java.util.Map;
7
8 import com.fasterxml.jackson.core.JsonParser;
9 import com.fasterxml.jackson.core.JsonProcessingException;
10 import com.fasterxml.jackson.core.JsonToken;
11 import com.fasterxml.jackson.databind.AnnotationIntrospector;
12 import com.fasterxml.jackson.databind.BeanProperty;
13 import com.fasterxml.jackson.databind.DeserializationContext;
14 import com.fasterxml.jackson.databind.JavaType;
15 import com.fasterxml.jackson.databind.JsonDeserializer;
16 import com.fasterxml.jackson.databind.JsonMappingException;
17 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
18 import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
19 import com.fasterxml.jackson.databind.deser.ContextualKeyDeserializer;
20 import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
21 import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
22 import com.fasterxml.jackson.databind.deser.ValueInstantiator;
23 import com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator;
24 import com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer;
25 import com.fasterxml.jackson.databind.deser.std.ContainerDeserializerBase;
26 import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
27 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
28 import com.fasterxml.jackson.databind.util.ArrayBuilders;
29
30
31
32
33
34
35
36
37
38
39 @JacksonStdImpl
40 public class KeyValueMapDeserializer extends
41 ContainerDeserializerBase<Map<Object, Object>> implements
42 ContextualDeserializer, ResolvableDeserializer, MapLabels {
43
44
45 private static final long serialVersionUID = 6589120424431005028L;
46
47 protected final JavaType _mapType;
48
49
50
51
52
53 protected final JsonDeserializer<Object> _keyDeserializer;
54
55
56
57
58
59
60
61 protected boolean _standardStringKey;
62
63
64
65
66 protected final JsonDeserializer<Object> _valueDeserializer;
67
68
69
70
71
72 protected final TypeDeserializer _valueTypeDeserializer;
73
74
75
76 protected final ValueInstantiator _valueInstantiator;
77
78 protected final boolean _hasDefaultCreator;
79
80
81
82
83
84 protected JsonDeserializer<Object> _delegateDeserializer;
85
86
87
88
89
90
91 protected PropertyBasedCreator _propertyBasedCreator;
92
93
94
95 protected HashSet<String> _ignorableProperties;
96
97
98
99
100
101
102 @SuppressWarnings("deprecation")
103 public KeyValueMapDeserializer(JavaType mapType,
104 ValueInstantiator valueInstantiator,
105 JsonDeserializer<Object> keyDeser,
106 JsonDeserializer<Object> valueDeser, TypeDeserializer valueTypeDeser) {
107 super(Map.class);
108 _mapType = mapType;
109 _keyDeserializer = keyDeser;
110 _valueDeserializer = valueDeser;
111 _valueTypeDeserializer = valueTypeDeser;
112 _valueInstantiator = valueInstantiator;
113 _hasDefaultCreator = false;
114 _delegateDeserializer = null;
115 _propertyBasedCreator = null;
116 _standardStringKey = _isStdKeyDeser(mapType, keyDeser);
117 }
118
119
120
121
122
123 @SuppressWarnings("deprecation")
124 protected KeyValueMapDeserializer(KeyValueMapDeserializer src) {
125 super(src._valueClass);
126 _mapType = src._mapType;
127 _keyDeserializer = src._keyDeserializer;
128 _valueDeserializer = src._valueDeserializer;
129 _valueTypeDeserializer = src._valueTypeDeserializer;
130 _valueInstantiator = src._valueInstantiator;
131 _propertyBasedCreator = src._propertyBasedCreator;
132 _delegateDeserializer = src._delegateDeserializer;
133 _hasDefaultCreator = src._hasDefaultCreator;
134
135 _ignorableProperties = src._ignorableProperties;
136
137 _standardStringKey = src._standardStringKey;
138 }
139
140 @SuppressWarnings("deprecation")
141 protected KeyValueMapDeserializer(KeyValueMapDeserializer src,
142 ValueInstantiator valueInstantiator,
143 JsonDeserializer<Object> keyDeser,
144 JsonDeserializer<Object> valueDeser,
145 TypeDeserializer valueTypeDeser, HashSet<String> ignorable) {
146 super(src._valueClass);
147 _mapType = src._mapType;
148 _keyDeserializer = keyDeser;
149 _valueDeserializer = valueDeser;
150 _valueTypeDeserializer = valueTypeDeser;
151 _valueInstantiator = valueInstantiator;
152 _propertyBasedCreator = src._propertyBasedCreator;
153 _delegateDeserializer = src._delegateDeserializer;
154 _hasDefaultCreator = src._hasDefaultCreator;
155 _ignorableProperties = ignorable;
156
157 _standardStringKey = _isStdKeyDeser(_mapType, keyDeser);
158 }
159
160
161
162
163
164 @SuppressWarnings("unchecked")
165 protected KeyValueMapDeserializer withResolved(
166 JsonDeserializer<?> keyDeser, TypeDeserializer valueTypeDeser,
167 JsonDeserializer<?> valueDeser, ValueInstantiator vi, HashSet<String> ignorable) {
168
169 if ((_keyDeserializer == keyDeser)
170 && (_valueDeserializer == valueDeser)
171 && (_valueTypeDeserializer == valueTypeDeser)
172 && (_ignorableProperties == ignorable)
173 && (_valueInstantiator == vi)) {
174 return this;
175 }
176 return new KeyValueMapDeserializer(this,
177 vi,
178 (JsonDeserializer<Object>) keyDeser,
179 (JsonDeserializer<Object>) valueDeser, valueTypeDeser,
180 ignorable);
181 }
182
183
184
185
186
187 protected final boolean _isStdKeyDeser(JavaType mapType,
188 JsonDeserializer<Object> keyDeser) {
189 if (keyDeser == null) {
190 return true;
191 }
192 JavaType keyType = mapType.getKeyType();
193 if (keyType == null) {
194 return true;
195 }
196 Class<?> rawKeyType = keyType.getRawClass();
197 return ((rawKeyType == String.class || rawKeyType == Object.class) && _isDefaultKeyDeserializer(keyDeser));
198 }
199
200 protected boolean _isDefaultKeyDeserializer(
201 JsonDeserializer<Object> keyDeser) {
202 return (keyDeser != null && keyDeser.getClass().getAnnotation(
203 JacksonStdImpl.class) != null);
204 }
205
206 public void setIgnorableProperties(String[] ignorable) {
207 _ignorableProperties = (ignorable == null || ignorable.length == 0) ? null
208 : ArrayBuilders.arrayToSet(ignorable);
209 }
210
211
212
213
214
215
216
217
218 public void resolve(DeserializationContext ctxt)
219 throws JsonMappingException {
220
221
222 final ValueInstantiator valueInstantiator = ctxt.getFactory().findValueInstantiator(ctxt, ctxt.getConfig().introspectForCreation(_mapType));
223
224 if (valueInstantiator.canCreateUsingDelegate()) {
225 JavaType delegateType = valueInstantiator.getDelegateType(ctxt
226 .getConfig());
227 if (delegateType == null) {
228 throw new IllegalArgumentException(
229 "Invalid delegate-creator definition for "
230 + _mapType
231 + ": value instantiator ("
232 + valueInstantiator.getClass().getName()
233 + ") returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'");
234 }
235
236
237
238
239
240 _delegateDeserializer = findDeserializer(ctxt, delegateType, null);
241 }
242 if (valueInstantiator.canCreateFromObjectWith()) {
243 SettableBeanProperty[] creatorProps = valueInstantiator
244 .getFromObjectArguments(ctxt.getConfig());
245 _propertyBasedCreator = PropertyBasedCreator.construct(ctxt,
246 valueInstantiator, creatorProps);
247 }
248 _standardStringKey = _isStdKeyDeser(_mapType, _keyDeserializer);
249 }
250
251
252
253
254
255
256 public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
257 BeanProperty property) throws JsonMappingException {
258 JsonDeserializer<?> kd = _keyDeserializer;
259 if (kd == null) {
260 kd = ctxt.findContextualValueDeserializer(_mapType.getKeyType(),
261 property);
262 } else {
263 if (kd instanceof ContextualKeyDeserializer) {
264 kd = ((ContextualDeserializer) kd).createContextual(ctxt,
265 property);
266 }
267 }
268 JsonDeserializer<?> vd = _valueDeserializer;
269 if (vd == null) {
270 vd = ctxt.findContextualValueDeserializer(
271 _mapType.getContentType(), property);
272 } else {
273 if (vd instanceof ContextualDeserializer) {
274 vd = ((ContextualDeserializer) vd).createContextual(ctxt,
275 property);
276 }
277 }
278 TypeDeserializer vtd = _valueTypeDeserializer;
279 if (vtd != null) {
280 vtd = vtd.forProperty(property);
281 }
282 HashSet<String> ignored = _ignorableProperties;
283 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
284 if (intr != null && property != null) {
285 String[] moreToIgnore = intr.findPropertiesToIgnore(property
286 .getMember());
287 if (moreToIgnore != null) {
288 ignored = (ignored == null) ? new HashSet<String>()
289 : new HashSet<String>(ignored);
290 for (String str : moreToIgnore) {
291 ignored.add(str);
292 }
293 }
294 }
295
296 ValueInstantiator vi = _valueInstantiator;
297 if (vi == null) {
298 vi = ctxt.getFactory().findValueInstantiator(ctxt, ctxt.getConfig().introspectForCreation(_mapType));
299 }
300 return withResolved(kd, vtd, vd, vi, ignored);
301 }
302
303
304
305
306
307
308
309 @Override
310 public JavaType getContentType() {
311 return _mapType.getContentType();
312 }
313
314 @Override
315 public JsonDeserializer<Object> getContentDeserializer() {
316 return _valueDeserializer;
317 }
318
319
320
321
322
323
324
325 @Override
326 @SuppressWarnings("unchecked")
327 public Map<Object, Object> deserialize(JsonParser jp,
328 DeserializationContext ctxt) throws IOException,
329 JsonProcessingException {
330
331 if (_propertyBasedCreator != null) {
332 return _deserializeUsingCreator(jp, ctxt);
333 }
334 if (_delegateDeserializer != null) {
335 return (Map<Object, Object>) _valueInstantiator
336 .createUsingDelegate(ctxt,
337 _delegateDeserializer.deserialize(jp, ctxt));
338 }
339 if (!_hasDefaultCreator && !_valueInstantiator.canCreateUsingDefault()) {
340 throw ctxt.instantiationException(getMapClass(),
341 "No default constructor found");
342 }
343
344 JsonToken t = jp.getCurrentToken();
345 if (t != JsonToken.START_ARRAY && t != JsonToken.START_OBJECT
346 && t != JsonToken.END_ARRAY) {
347
348 if (t == JsonToken.VALUE_STRING) {
349 return (Map<Object, Object>) _valueInstantiator
350 .createFromString(ctxt, jp.getText());
351 }
352 throw ctxt.mappingException(getMapClass());
353 }
354 final Map<Object, Object> result = (Map<Object, Object>) _valueInstantiator
355 .createUsingDefault(ctxt);
356 if (_standardStringKey) {
357 _readAndBindStringMap(jp, ctxt, result);
358 return result;
359 }
360 _readAndBind(jp, ctxt, result);
361 return result;
362 }
363
364 @Override
365 public Map<Object, Object> deserialize(JsonParser jp,
366 DeserializationContext ctxt, Map<Object, Object> result)
367 throws IOException, JsonProcessingException {
368
369 JsonToken t = jp.getCurrentToken();
370 if (t != JsonToken.START_ARRAY && t != JsonToken.START_OBJECT) {
371 throw ctxt.mappingException(getMapClass());
372 }
373 if (_standardStringKey) {
374 _readAndBindStringMap(jp, ctxt, result);
375 return result;
376 }
377 _readAndBind(jp, ctxt, result);
378 return result;
379 }
380
381 @Override
382 public Object deserializeWithType(JsonParser jp,
383 DeserializationContext ctxt, TypeDeserializer typeDeserializer)
384 throws IOException, JsonProcessingException {
385
386 return typeDeserializer.deserializeTypedFromObject(jp, ctxt);
387 }
388
389
390
391
392
393
394
395 @SuppressWarnings("unchecked")
396 public final Class<?> getMapClass() {
397 return (Class<Map<Object, Object>>) _mapType.getRawClass();
398 }
399
400 @Override
401 public JavaType getValueType() {
402 return _mapType;
403 }
404
405
406
407
408
409
410 protected final void _readAndBind(JsonParser jp,
411 DeserializationContext ctxt, Map<Object, Object> result)
412 throws IOException, JsonProcessingException {
413 JsonToken t = jp.getCurrentToken();
414 if (t == JsonToken.START_ARRAY) {
415 t = jp.nextToken();
416 }
417 final JsonDeserializer<Object> keyDes = _keyDeserializer;
418 final JsonDeserializer<Object> valueDes = _valueDeserializer;
419 final TypeDeserializer typeDeser = _valueTypeDeserializer;
420 for (; t == JsonToken.START_OBJECT; t = jp.nextToken()) {
421 Object key = null, value = null;
422
423 for (t = jp.nextToken(); t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
424
425 String fieldName = jp.getCurrentName();
426 t = jp.nextToken();
427 if (_ignorableProperties != null
428 && _ignorableProperties.contains(fieldName)) {
429 jp.skipChildren();
430 continue;
431 }
432
433 if (MAP_KEY_NAME.equals(fieldName)) {
434 if (t == JsonToken.VALUE_NULL) {
435
436 key = null;
437 } else {
438 key = keyDes.deserialize(jp, ctxt);
439 }
440 } else if (MAP_VALUE_NAME.equals(fieldName)) {
441
442
443 if (t == JsonToken.VALUE_NULL) {
444 value = null;
445 } else if (typeDeser == null) {
446 value = valueDes.deserialize(jp, ctxt);
447 } else {
448 value = valueDes.deserializeWithType(jp, ctxt,
449 typeDeser);
450 }
451 }
452
453
454
455
456
457 if (key != null) {
458 result.put(key, value);
459 }
460 }
461 }
462 }
463
464
465
466
467
468 protected final void _readAndBindStringMap(JsonParser jp,
469 DeserializationContext ctxt, Map<Object, Object> result)
470 throws IOException, JsonProcessingException {
471 JsonToken t = jp.getCurrentToken();
472 if (t == JsonToken.START_OBJECT) {
473 t = jp.nextToken();
474 }
475 final JsonDeserializer<Object> valueDes = _valueDeserializer;
476 final TypeDeserializer typeDeser = _valueTypeDeserializer;
477 for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
478
479 String fieldName = jp.getCurrentName();
480
481 t = jp.nextToken();
482 if (_ignorableProperties != null
483 && _ignorableProperties.contains(fieldName)) {
484 jp.skipChildren();
485 continue;
486 }
487
488 Object value;
489 if (t == JsonToken.VALUE_NULL) {
490 value = null;
491 } else if (typeDeser == null) {
492 value = valueDes.deserialize(jp, ctxt);
493 } else {
494 value = valueDes.deserializeWithType(jp, ctxt, typeDeser);
495 }
496 result.put(fieldName, value);
497 }
498 }
499
500 @SuppressWarnings("unchecked")
501 public Map<Object, Object> _deserializeUsingCreator(JsonParser jp,
502 DeserializationContext ctxt) throws IOException,
503 JsonProcessingException {
504 final PropertyBasedCreator creator = _propertyBasedCreator;
505
506 PropertyValueBuffer buffer = creator.startBuilding(jp, ctxt, null);
507
508 JsonToken t = jp.getCurrentToken();
509 if (t == JsonToken.START_OBJECT) {
510 t = jp.nextToken();
511 }
512 final JsonDeserializer<Object> valueDes = _valueDeserializer;
513 final TypeDeserializer typeDeser = _valueTypeDeserializer;
514 for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
515 String propName = jp.getCurrentName();
516 t = jp.nextToken();
517 if (_ignorableProperties != null
518 && _ignorableProperties.contains(propName)) {
519 jp.skipChildren();
520 continue;
521 }
522
523 SettableBeanProperty prop = creator.findCreatorProperty(propName);
524 if (prop != null) {
525
526 Object value = prop.deserialize(jp, ctxt);
527 if (buffer.assignParameter(prop.getCreatorIndex(), value)) {
528 jp.nextToken();
529 Map<Object, Object> result;
530 try {
531 result = (Map<Object, Object>) creator.build(ctxt,
532 buffer);
533 } catch (Exception e) {
534 wrapAndThrow(e, _mapType.getRawClass());
535 return null;
536 }
537 _readAndBind(jp, ctxt, result);
538 return result;
539 }
540 continue;
541 }
542 Object key = _keyDeserializer.deserialize(jp, ctxt);
543 Object value;
544 if (t == JsonToken.VALUE_NULL) {
545 value = null;
546 } else if (typeDeser == null) {
547 value = valueDes.deserialize(jp, ctxt);
548 } else {
549 value = valueDes.deserializeWithType(jp, ctxt, typeDeser);
550 }
551 buffer.bufferMapProperty(key, value);
552 }
553
554
555 try {
556 return (Map<Object, Object>) creator.build(ctxt, buffer);
557 } catch (Exception e) {
558 wrapAndThrow(e, _mapType.getRawClass());
559 return null;
560 }
561 }
562
563
564 protected void wrapAndThrow(Throwable t, Object ref) throws IOException {
565
566 while (t instanceof InvocationTargetException && t.getCause() != null) {
567 t = t.getCause();
568 }
569
570 if (t instanceof Error) {
571 throw (Error) t;
572 }
573
574 if (t instanceof IOException && !(t instanceof JsonMappingException)) {
575 throw (IOException) t;
576 }
577 throw JsonMappingException.wrapWithPath(t, ref, null);
578 }
579 }