Coverage Report - com.buckosoft.PicMan.service.support.KeyValueMapDeserializer
 
Classes in this File Line Coverage Branch Coverage Complexity
KeyValueMapDeserializer
0%
0/216
0%
0/140
5.4
 
 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  
  * Basic serializer that can take Json "Object" structure and construct a
 32  
  * {@link java.util.Map} instance, with typed contents.
 33  
  * <p>
 34  
  * Note: for untyped content (one indicated by passing Object.class as the
 35  
  * type), {@link UntypedObjectDeserializer} is used instead. It can also
 36  
  * construct {@link java.util.Map}s, but not with specific POJO types, only
 37  
  * other containers and primitives/wrappers.
 38  
  */
 39  0
 @JacksonStdImpl
 40  
 public class KeyValueMapDeserializer extends
 41  
                 ContainerDeserializerBase<Map<Object, Object>> implements
 42  
                 ContextualDeserializer, ResolvableDeserializer, MapLabels {
 43  
         // // Configuration: typing, deserializers
 44  
 
 45  
         private static final long serialVersionUID = 6589120424431005028L;
 46  
 
 47  
         protected final JavaType _mapType;
 48  
 
 49  
         /**
 50  
          * Key deserializer to use; either passed via constructor (when indicated by
 51  
          * annotations), or resolved when {@link #resolve} is called;
 52  
          */
 53  
         protected final JsonDeserializer<Object> _keyDeserializer;
 54  
 
 55  
         /**
 56  
          * Flag set to indicate that the key type is {@link java.lang.String} (or
 57  
          * {@link java.lang.Object}, for which String is acceptable), <b>and</b>
 58  
          * that the default Jackson key deserializer would be used. If both are
 59  
          * true, can optimize handling.
 60  
          */
 61  
         protected boolean _standardStringKey;
 62  
 
 63  
         /**
 64  
          * Value deserializer.
 65  
          */
 66  
         protected final JsonDeserializer<Object> _valueDeserializer;
 67  
 
 68  
         /**
 69  
          * If value instances have polymorphic type information, this is the type
 70  
          * deserializer that can handle it
 71  
          */
 72  
         protected final TypeDeserializer _valueTypeDeserializer;
 73  
 
 74  
         // // Instance construction settings:
 75  
 
 76  
         protected final ValueInstantiator _valueInstantiator;
 77  
 
 78  
         protected final boolean _hasDefaultCreator;
 79  
 
 80  
         /**
 81  
          * Deserializer that is used iff delegate-based creator is to be used for
 82  
          * deserializing from JSON Object.
 83  
          */
 84  
         protected JsonDeserializer<Object> _delegateDeserializer;
 85  
 
 86  
         /**
 87  
          * If the Map is to be instantiated using non-default constructor or factory
 88  
          * method that takes one or more named properties as argument(s), this
 89  
          * creator is used for instantiation.
 90  
          */
 91  
         protected PropertyBasedCreator _propertyBasedCreator;
 92  
 
 93  
         // // Any properties to ignore if seen?
 94  
 
 95  
         protected HashSet<String> _ignorableProperties;
 96  
 
 97  
         /*
 98  
          * /********************************************************** /* Life-cycle
 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  0
                 super(Map.class);
 108  0
                 _mapType = mapType;
 109  0
                 _keyDeserializer = keyDeser;
 110  0
                 _valueDeserializer = valueDeser;
 111  0
                 _valueTypeDeserializer = valueTypeDeser;
 112  0
                 _valueInstantiator = valueInstantiator;
 113  0
                 _hasDefaultCreator = false;//valueInstantiator.canCreateUsingDefault();
 114  0
                 _delegateDeserializer = null;
 115  0
                 _propertyBasedCreator = null;
 116  0
                 _standardStringKey = _isStdKeyDeser(mapType, keyDeser);
 117  0
         }
 118  
 
 119  
         /**
 120  
          * Copy-constructor that can be used by sub-classes to allow copy-on-write
 121  
          * styling copying of settings of an existing instance.
 122  
          */
 123  
         @SuppressWarnings("deprecation")
 124  
         protected KeyValueMapDeserializer(KeyValueMapDeserializer src) {
 125  0
                 super(src._valueClass);
 126  0
                 _mapType = src._mapType;
 127  0
                 _keyDeserializer = src._keyDeserializer;
 128  0
                 _valueDeserializer = src._valueDeserializer;
 129  0
                 _valueTypeDeserializer = src._valueTypeDeserializer;
 130  0
                 _valueInstantiator = src._valueInstantiator;
 131  0
                 _propertyBasedCreator = src._propertyBasedCreator;
 132  0
                 _delegateDeserializer = src._delegateDeserializer;
 133  0
                 _hasDefaultCreator = src._hasDefaultCreator;
 134  
                 // should we make a copy here?
 135  0
                 _ignorableProperties = src._ignorableProperties;
 136  
 
 137  0
                 _standardStringKey = src._standardStringKey;
 138  0
         }
 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  0
                 super(src._valueClass);
 147  0
                 _mapType = src._mapType;
 148  0
                 _keyDeserializer = keyDeser;
 149  0
                 _valueDeserializer = valueDeser;
 150  0
                 _valueTypeDeserializer = valueTypeDeser;
 151  0
                 _valueInstantiator = valueInstantiator;
 152  0
                 _propertyBasedCreator = src._propertyBasedCreator;
 153  0
                 _delegateDeserializer = src._delegateDeserializer;
 154  0
                 _hasDefaultCreator = src._hasDefaultCreator;
 155  0
                 _ignorableProperties = ignorable;
 156  
 
 157  0
                 _standardStringKey = _isStdKeyDeser(_mapType, keyDeser);
 158  0
         }
 159  
 
 160  
         /**
 161  
          * Fluent factory method used to create a copy with slightly different
 162  
          * settings. When sub-classing, MUST be overridden.
 163  
          */
 164  
         @SuppressWarnings("unchecked")
 165  
         protected KeyValueMapDeserializer withResolved(
 166  
                         JsonDeserializer<?> keyDeser, TypeDeserializer valueTypeDeser,
 167  
                         JsonDeserializer<?> valueDeser, ValueInstantiator vi, HashSet<String> ignorable) {
 168  
 
 169  0
                 if ((_keyDeserializer == keyDeser)
 170  
                                 && (_valueDeserializer == valueDeser)
 171  
                                 && (_valueTypeDeserializer == valueTypeDeser)
 172  
                                 && (_ignorableProperties == ignorable)
 173  
                                 && (_valueInstantiator == vi)) {
 174  0
                         return this;
 175  
                 }
 176  0
                 return new KeyValueMapDeserializer(this,
 177  
                                 vi,
 178  
                                 (JsonDeserializer<Object>) keyDeser,
 179  
                                 (JsonDeserializer<Object>) valueDeser, valueTypeDeser,
 180  
                                 ignorable);
 181  
         }
 182  
 
 183  
         /**
 184  
          * Helper method used to check whether we can just use the default key
 185  
          * deserialization, where JSON String becomes Java String.
 186  
          */
 187  
         protected final boolean _isStdKeyDeser(JavaType mapType,
 188  
                         JsonDeserializer<Object> keyDeser) {
 189  0
                 if (keyDeser == null) {
 190  0
                         return true;
 191  
                 }
 192  0
                 JavaType keyType = mapType.getKeyType();
 193  0
                 if (keyType == null) { // assumed to be Object
 194  0
                         return true;
 195  
                 }
 196  0
                 Class<?> rawKeyType = keyType.getRawClass();
 197  0
                 return ((rawKeyType == String.class || rawKeyType == Object.class) && _isDefaultKeyDeserializer(keyDeser));
 198  
         }
 199  
 
 200  
         protected boolean _isDefaultKeyDeserializer(
 201  
                         JsonDeserializer<Object> keyDeser) {
 202  0
                 return (keyDeser != null && keyDeser.getClass().getAnnotation(
 203  
                                 JacksonStdImpl.class) != null);
 204  
         }
 205  
 
 206  
         public void setIgnorableProperties(String[] ignorable) {
 207  0
                 _ignorableProperties = (ignorable == null || ignorable.length == 0) ? null
 208  0
                                 : ArrayBuilders.arrayToSet(ignorable);
 209  0
         }
 210  
 
 211  
         /*
 212  
          * /********************************************************** /*
 213  
          * Validation, post-processing (ResolvableDeserializer)
 214  
          * /**********************************************************
 215  
          */
 216  
 
 217  
         // @Override
 218  
         public void resolve(DeserializationContext ctxt)
 219  
                         throws JsonMappingException {
 220  
                 // May need to resolve types for delegate- and/or property-based
 221  
                 // creators:
 222  0
                 final ValueInstantiator valueInstantiator = ctxt.getFactory().findValueInstantiator(ctxt, ctxt.getConfig().introspectForCreation(_mapType));
 223  
                 
 224  0
                 if (valueInstantiator.canCreateUsingDelegate()) {
 225  0
                         JavaType delegateType = valueInstantiator.getDelegateType(ctxt
 226  0
                                         .getConfig());
 227  0
                         if (delegateType == null) {
 228  0
                                 throw new IllegalArgumentException(
 229  
                                                 "Invalid delegate-creator definition for "
 230  
                                                                 + _mapType
 231  
                                                                 + ": value instantiator ("
 232  0
                                                                 + valueInstantiator.getClass().getName()
 233  
                                                                 + ") returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'");
 234  
                         }
 235  
                         /*
 236  
                          * Theoretically should be able to get CreatorProperty for delegate
 237  
                          * parameter to pass; but things get tricky because DelegateCreator
 238  
                          * may contain injectable values. So, for now, let's pass nothing.
 239  
                          */
 240  0
                         _delegateDeserializer = findDeserializer(ctxt, delegateType, null);
 241  
                 }
 242  0
                 if (valueInstantiator.canCreateFromObjectWith()) {
 243  0
                         SettableBeanProperty[] creatorProps = valueInstantiator
 244  0
                                         .getFromObjectArguments(ctxt.getConfig());
 245  0
                         _propertyBasedCreator = PropertyBasedCreator.construct(ctxt,
 246  
                                         valueInstantiator, creatorProps);
 247  
                 }
 248  0
                 _standardStringKey = _isStdKeyDeser(_mapType, _keyDeserializer);
 249  0
         }
 250  
 
 251  
         /**
 252  
          * Method called to finalize setup of this deserializer, when it is known
 253  
          * for which property deserializer is needed for.
 254  
          */
 255  
         // @Override
 256  
         public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
 257  
                         BeanProperty property) throws JsonMappingException {
 258  0
                 JsonDeserializer<?> kd = _keyDeserializer;
 259  0
                 if (kd == null) {
 260  0
                         kd = ctxt.findContextualValueDeserializer(_mapType.getKeyType(),
 261  
                                         property);
 262  
                 } else {
 263  0
                         if (kd instanceof ContextualKeyDeserializer) {
 264  0
                                 kd = ((ContextualDeserializer) kd).createContextual(ctxt,
 265  
                                                 property);
 266  
                         }
 267  
                 }
 268  0
                 JsonDeserializer<?> vd = _valueDeserializer;
 269  0
                 if (vd == null) {
 270  0
                         vd = ctxt.findContextualValueDeserializer(
 271  0
                                         _mapType.getContentType(), property);
 272  
                 } else { // if directly assigned, probably not yet contextual, so:
 273  0
                         if (vd instanceof ContextualDeserializer) {
 274  0
                                 vd = ((ContextualDeserializer) vd).createContextual(ctxt,
 275  
                                                 property);
 276  
                         }
 277  
                 }
 278  0
                 TypeDeserializer vtd = _valueTypeDeserializer;
 279  0
                 if (vtd != null) {
 280  0
                         vtd = vtd.forProperty(property);
 281  
                 }
 282  0
                 HashSet<String> ignored = _ignorableProperties;
 283  0
                 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
 284  0
                 if (intr != null && property != null) {
 285  0
                         String[] moreToIgnore = intr.findPropertiesToIgnore(property
 286  0
                                         .getMember());
 287  0
                         if (moreToIgnore != null) {
 288  0
                                 ignored = (ignored == null) ? new HashSet<String>()
 289  
                                                 : new HashSet<String>(ignored);
 290  0
                                 for (String str : moreToIgnore) {
 291  0
                                         ignored.add(str);
 292  
                                 }
 293  
                         }
 294  
                 }
 295  
                 
 296  0
                 ValueInstantiator vi = _valueInstantiator;
 297  0
                 if (vi == null) {
 298  0
                         vi = ctxt.getFactory().findValueInstantiator(ctxt, ctxt.getConfig().introspectForCreation(_mapType));
 299  
                 }
 300  0
                 return withResolved(kd, vtd, vd, vi, ignored);
 301  
         }
 302  
 
 303  
         /*
 304  
          * /********************************************************** /*
 305  
          * ContainerDeserializerBase API
 306  
          * /**********************************************************
 307  
          */
 308  
 
 309  
         @Override
 310  
         public JavaType getContentType() {
 311  0
                 return _mapType.getContentType();
 312  
         }
 313  
 
 314  
         @Override
 315  
         public JsonDeserializer<Object> getContentDeserializer() {
 316  0
                 return _valueDeserializer;
 317  
         }
 318  
 
 319  
         /*
 320  
          * /********************************************************** /*
 321  
          * JsonDeserializer API
 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  0
                 if (_propertyBasedCreator != null) {
 332  0
                         return _deserializeUsingCreator(jp, ctxt);
 333  
                 }
 334  0
                 if (_delegateDeserializer != null) {
 335  0
                         return (Map<Object, Object>) _valueInstantiator
 336  0
                                         .createUsingDelegate(ctxt,
 337  0
                                                         _delegateDeserializer.deserialize(jp, ctxt));
 338  
                 }
 339  0
                 if (!_hasDefaultCreator && !_valueInstantiator.canCreateUsingDefault()) {
 340  0
                         throw ctxt.instantiationException(getMapClass(),
 341  
                                         "No default constructor found");
 342  
                 }
 343  
                 // Ok: must point to START_ARRAY, START_OBJECT or END_ARRAY
 344  0
                 JsonToken t = jp.getCurrentToken();
 345  0
                 if (t != JsonToken.START_ARRAY && t != JsonToken.START_OBJECT
 346  
                                 && t != JsonToken.END_ARRAY) {
 347  
                         // [JACKSON-620] (empty) String may be ok however:
 348  0
                         if (t == JsonToken.VALUE_STRING) {
 349  0
                                 return (Map<Object, Object>) _valueInstantiator
 350  0
                                                 .createFromString(ctxt, jp.getText());
 351  
                         }
 352  0
                         throw ctxt.mappingException(getMapClass());
 353  
                 }
 354  0
                 final Map<Object, Object> result = (Map<Object, Object>) _valueInstantiator
 355  0
                                 .createUsingDefault(ctxt);
 356  0
                 if (_standardStringKey) {
 357  0
                         _readAndBindStringMap(jp, ctxt, result);
 358  0
                         return result;
 359  
                 }
 360  0
                 _readAndBind(jp, ctxt, result);
 361  0
                 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  
                 // Ok: must point to START_ARRAY or START_OBJECT
 369  0
                 JsonToken t = jp.getCurrentToken();
 370  0
                 if (t != JsonToken.START_ARRAY && t != JsonToken.START_OBJECT) {
 371  0
                         throw ctxt.mappingException(getMapClass());
 372  
                 }
 373  0
                 if (_standardStringKey) {
 374  0
                         _readAndBindStringMap(jp, ctxt, result);
 375  0
                         return result;
 376  
                 }
 377  0
                 _readAndBind(jp, ctxt, result);
 378  0
                 return result;
 379  
         }
 380  
 
 381  
         @Override
 382  
         public Object deserializeWithType(JsonParser jp,
 383  
                         DeserializationContext ctxt, TypeDeserializer typeDeserializer)
 384  
                         throws IOException, JsonProcessingException {
 385  
                 // In future could check current token... for now this should be enough:
 386  0
                 return typeDeserializer.deserializeTypedFromObject(jp, ctxt);
 387  
         }
 388  
 
 389  
         /*
 390  
          * /********************************************************** /* Other
 391  
          * public accessors
 392  
          * /**********************************************************
 393  
          */
 394  
 
 395  
         @SuppressWarnings("unchecked")
 396  
         public final Class<?> getMapClass() {
 397  0
                 return (Class<Map<Object, Object>>) _mapType.getRawClass();
 398  
         }
 399  
 
 400  
         @Override
 401  
         public JavaType getValueType() {
 402  0
                 return _mapType;
 403  
         }
 404  
 
 405  
         /*
 406  
          * /********************************************************** /* Internal
 407  
          * methods /**********************************************************
 408  
          */
 409  
 
 410  
         protected final void _readAndBind(JsonParser jp,
 411  
                         DeserializationContext ctxt, Map<Object, Object> result)
 412  
                         throws IOException, JsonProcessingException {
 413  0
                 JsonToken t = jp.getCurrentToken();
 414  0
                 if (t == JsonToken.START_ARRAY) {
 415  0
                         t = jp.nextToken();
 416  
                 }
 417  0
                 final JsonDeserializer<Object> keyDes = _keyDeserializer;
 418  0
                 final JsonDeserializer<Object> valueDes = _valueDeserializer;
 419  0
                 final TypeDeserializer typeDeser = _valueTypeDeserializer;
 420  0
                 for (; t == JsonToken.START_OBJECT; t = jp.nextToken()) {
 421  0
                         Object key = null, value = null;
 422  
                         
 423  0
                         for (t = jp.nextToken(); t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
 424  
                                 // Must point to field name
 425  0
                                 String fieldName = jp.getCurrentName();
 426  0
                                 t = jp.nextToken();
 427  0
                                 if (_ignorableProperties != null
 428  0
                                                 && _ignorableProperties.contains(fieldName)) {
 429  0
                                         jp.skipChildren();
 430  0
                                         continue;
 431  
                                 }
 432  
 
 433  0
                                 if (MAP_KEY_NAME.equals(fieldName)) {
 434  0
                                         if (t == JsonToken.VALUE_NULL) {
 435  
                                                 // handle null keys
 436  0
                                                 key = null;
 437  
                                         } else {
 438  0
                                                 key = keyDes.deserialize(jp, ctxt);
 439  
                                         }
 440  0
                                 } else if (MAP_VALUE_NAME.equals(fieldName)) {
 441  
                                         // Note: must handle null explicitly here; value
 442  
                                         // deserializers won't
 443  0
                                         if (t == JsonToken.VALUE_NULL) {
 444  0
                                                 value = null;
 445  0
                                         } else if (typeDeser == null) {
 446  0
                                                 value = valueDes.deserialize(jp, ctxt);
 447  
                                         } else {
 448  0
                                                 value = valueDes.deserializeWithType(jp, ctxt,
 449  
                                                                 typeDeser);
 450  
                                         }
 451  
                                 }
 452  
                                 /*
 453  
                                  * !!! 23-Dec-2008, tatu: should there be an option to verify
 454  
                                  * that there are no duplicate field names? (and/or what to do,
 455  
                                  * keep-first or keep-last)
 456  
                                  */
 457  0
                                 if (key != null) {
 458  0
                                         result.put(key, value);
 459  
                                 }
 460  
                         }
 461  
                 }
 462  0
         }
 463  
 
 464  
         /**
 465  
          * Optimized method used when keys can be deserialized as plain old
 466  
          * {@link java.lang.String}s, and there is no custom deserialized specified.
 467  
          */
 468  
         protected final void _readAndBindStringMap(JsonParser jp,
 469  
                         DeserializationContext ctxt, Map<Object, Object> result)
 470  
                         throws IOException, JsonProcessingException {
 471  0
                 JsonToken t = jp.getCurrentToken();
 472  0
                 if (t == JsonToken.START_OBJECT) {
 473  0
                         t = jp.nextToken();
 474  
                 }
 475  0
                 final JsonDeserializer<Object> valueDes = _valueDeserializer;
 476  0
                 final TypeDeserializer typeDeser = _valueTypeDeserializer;
 477  0
                 for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
 478  
                         // Must point to field name
 479  0
                         String fieldName = jp.getCurrentName();
 480  
                         // And then the value...
 481  0
                         t = jp.nextToken();
 482  0
                         if (_ignorableProperties != null
 483  0
                                         && _ignorableProperties.contains(fieldName)) {
 484  0
                                 jp.skipChildren();
 485  0
                                 continue;
 486  
                         }
 487  
                         // Note: must handle null explicitly here; value deserializers won't
 488  
                         Object value;
 489  0
                         if (t == JsonToken.VALUE_NULL) {
 490  0
                                 value = null;
 491  0
                         } else if (typeDeser == null) {
 492  0
                                 value = valueDes.deserialize(jp, ctxt);
 493  
                         } else {
 494  0
                                 value = valueDes.deserializeWithType(jp, ctxt, typeDeser);
 495  
                         }
 496  0
                         result.put(fieldName, value);
 497  
                 }
 498  0
         }
 499  
 
 500  
         @SuppressWarnings("unchecked")
 501  
         public Map<Object, Object> _deserializeUsingCreator(JsonParser jp,
 502  
                         DeserializationContext ctxt) throws IOException,
 503  
                         JsonProcessingException {
 504  0
                 final PropertyBasedCreator creator = _propertyBasedCreator;
 505  
                 // null -> no ObjectIdReader for Maps (yet?)
 506  0
                 PropertyValueBuffer buffer = creator.startBuilding(jp, ctxt, null);
 507  
 
 508  0
                 JsonToken t = jp.getCurrentToken();
 509  0
                 if (t == JsonToken.START_OBJECT) {
 510  0
                         t = jp.nextToken();
 511  
                 }
 512  0
                 final JsonDeserializer<Object> valueDes = _valueDeserializer;
 513  0
                 final TypeDeserializer typeDeser = _valueTypeDeserializer;
 514  0
                 for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
 515  0
                         String propName = jp.getCurrentName();
 516  0
                         t = jp.nextToken(); // to get to value
 517  0
                         if (_ignorableProperties != null
 518  0
                                         && _ignorableProperties.contains(propName)) {
 519  0
                                 jp.skipChildren(); // and skip it (in case of array/object)
 520  0
                                 continue;
 521  
                         }
 522  
                         // creator property?
 523  0
                         SettableBeanProperty prop = creator.findCreatorProperty(propName);
 524  0
                         if (prop != null) {
 525  
                                 // Last property to set?
 526  0
                                 Object value = prop.deserialize(jp, ctxt);
 527  0
                                 if (buffer.assignParameter(prop.getCreatorIndex(), value)) {
 528  0
                                         jp.nextToken();
 529  
                                         Map<Object, Object> result;
 530  
                                         try {
 531  0
                                                 result = (Map<Object, Object>) creator.build(ctxt,
 532  
                                                                 buffer);
 533  0
                                         } catch (Exception e) {
 534  0
                                                 wrapAndThrow(e, _mapType.getRawClass());
 535  0
                                                 return null;
 536  0
                                         }
 537  0
                                         _readAndBind(jp, ctxt, result);
 538  0
                                         return result;
 539  
                                 }
 540  
                                 continue;
 541  
                         }
 542  0
                         Object key = _keyDeserializer.deserialize(jp, ctxt);
 543  
                         Object value;
 544  0
                         if (t == JsonToken.VALUE_NULL) {
 545  0
                                 value = null;
 546  0
                         } else if (typeDeser == null) {
 547  0
                                 value = valueDes.deserialize(jp, ctxt);
 548  
                         } else {
 549  0
                                 value = valueDes.deserializeWithType(jp, ctxt, typeDeser);
 550  
                         }
 551  0
                         buffer.bufferMapProperty(key, value);
 552  
                 }
 553  
                 // end of JSON object?
 554  
                 // if so, can just construct and leave...
 555  
                 try {
 556  0
                         return (Map<Object, Object>) creator.build(ctxt, buffer);
 557  0
                 } catch (Exception e) {
 558  0
                         wrapAndThrow(e, _mapType.getRawClass());
 559  0
                         return null;
 560  
                 }
 561  
         }
 562  
 
 563  
         // note: copied form BeanDeserializer; should try to share somehow...
 564  
         protected void wrapAndThrow(Throwable t, Object ref) throws IOException {
 565  
                 // to handle StackOverflow:
 566  0
                 while (t instanceof InvocationTargetException && t.getCause() != null) {
 567  0
                         t = t.getCause();
 568  
                 }
 569  
                 // Errors and "plain" IOExceptions to be passed as is
 570  0
                 if (t instanceof Error) {
 571  0
                         throw (Error) t;
 572  
                 }
 573  
                 // ... except for mapping exceptions
 574  0
                 if (t instanceof IOException && !(t instanceof JsonMappingException)) {
 575  0
                         throw (IOException) t;
 576  
                 }
 577  0
                 throw JsonMappingException.wrapWithPath(t, ref, null);
 578  
         }
 579  
 }