@@ -324,6 +324,74 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, Typ
324
324
return ctxt .handleUnexpectedToken (Object .class , p );
325
325
}
326
326
327
+ @ SuppressWarnings ("unchecked" )
328
+ @ Override // since 2.9 (to support deep merge)
329
+ public Object deserialize (JsonParser p , DeserializationContext ctxt , Object intoValue )
330
+ throws IOException
331
+ {
332
+ switch (p .getCurrentTokenId ()) {
333
+ case JsonTokenId .ID_START_OBJECT :
334
+ case JsonTokenId .ID_FIELD_NAME :
335
+ // 28-Oct-2015, tatu: [databind#989] We may also be given END_OBJECT (similar to FIELD_NAME),
336
+ // if caller has advanced to the first token of Object, but for empty Object
337
+ case JsonTokenId .ID_END_OBJECT :
338
+ if (_mapDeserializer != null ) {
339
+ return _mapDeserializer .deserialize (p , ctxt , intoValue );
340
+ }
341
+ if (intoValue instanceof Map <?,?>) {
342
+ return mapObject (p , ctxt , (Map <Object ,Object >) intoValue );
343
+ }
344
+ return mapObject (p , ctxt );
345
+ case JsonTokenId .ID_START_ARRAY :
346
+ if (_listDeserializer != null ) {
347
+ return _listDeserializer .deserialize (p , ctxt , intoValue );
348
+ }
349
+ if (intoValue instanceof Collection <?>) {
350
+ return mapArray (p , ctxt , (Collection <Object >) intoValue );
351
+ }
352
+ if (ctxt .isEnabled (DeserializationFeature .USE_JAVA_ARRAY_FOR_JSON_ARRAY )) {
353
+ return mapArrayToArray (p , ctxt );
354
+ }
355
+ return mapArray (p , ctxt );
356
+ case JsonTokenId .ID_EMBEDDED_OBJECT :
357
+ return p .getEmbeddedObject ();
358
+ case JsonTokenId .ID_STRING :
359
+ if (_stringDeserializer != null ) {
360
+ return _stringDeserializer .deserialize (p , ctxt , intoValue );
361
+ }
362
+ return p .getText ();
363
+
364
+ case JsonTokenId .ID_NUMBER_INT :
365
+ if (_numberDeserializer != null ) {
366
+ return _numberDeserializer .deserialize (p , ctxt , intoValue );
367
+ }
368
+ if (ctxt .hasSomeOfFeatures (F_MASK_INT_COERCIONS )) {
369
+ return _coerceIntegral (p , ctxt );
370
+ }
371
+ return p .getNumberValue ();
372
+
373
+ case JsonTokenId .ID_NUMBER_FLOAT :
374
+ if (_numberDeserializer != null ) {
375
+ return _numberDeserializer .deserialize (p , ctxt , intoValue );
376
+ }
377
+ if (ctxt .isEnabled (DeserializationFeature .USE_BIG_DECIMAL_FOR_FLOATS )) {
378
+ return p .getDecimalValue ();
379
+ }
380
+ return p .getNumberValue ();
381
+ case JsonTokenId .ID_TRUE :
382
+ return Boolean .TRUE ;
383
+ case JsonTokenId .ID_FALSE :
384
+ return Boolean .FALSE ;
385
+
386
+ case JsonTokenId .ID_NULL :
387
+ // 21-Apr-2017, tatu: May need to consider "skip nulls" at some point but...
388
+ return null ;
389
+ default :
390
+ }
391
+ // easiest to just delegate to "dumb" version for the rest?
392
+ return deserialize (p , ctxt );
393
+ }
394
+
327
395
/*
328
396
/**********************************************************
329
397
/* Internal methods
@@ -373,6 +441,17 @@ protected Object mapArray(JsonParser p, DeserializationContext ctxt) throws IOEx
373
441
return result ;
374
442
}
375
443
444
+ protected Object mapArray (JsonParser p , DeserializationContext ctxt ,
445
+ Collection <Object > result ) throws IOException
446
+ {
447
+ // we start by pointing to START_ARRAY. Also, no real merging; array/Collection
448
+ // just appends always
449
+ while (p .nextToken () != JsonToken .END_ARRAY ) {
450
+ result .add (deserialize (p , ctxt ));
451
+ }
452
+ return result ;
453
+ }
454
+
376
455
/**
377
456
* Method called to map a JSON Object into a Java value.
378
457
*/
@@ -455,6 +534,36 @@ protected Object[] mapArrayToArray(JsonParser p, DeserializationContext ctxt) th
455
534
return buffer .completeAndClearBuffer (values , ptr );
456
535
}
457
536
537
+ protected Object mapObject (JsonParser p , DeserializationContext ctxt ,
538
+ Map <Object ,Object > m ) throws IOException
539
+ {
540
+ JsonToken t = p .getCurrentToken ();
541
+ if (t == JsonToken .START_OBJECT ) {
542
+ t = p .nextToken ();
543
+ }
544
+ if (t == JsonToken .END_OBJECT ) {
545
+ return m ;
546
+ }
547
+ // NOTE: we are guaranteed to point to FIELD_NAME
548
+ String key = p .getCurrentName ();
549
+ do {
550
+ p .nextToken ();
551
+ // and possibly recursive merge here
552
+ Object old = m .get (key );
553
+ Object newV ;
554
+
555
+ if (old != null ) {
556
+ newV = deserialize (p , ctxt , old );
557
+ } else {
558
+ newV = deserialize (p , ctxt );
559
+ }
560
+ if (newV != old ) {
561
+ m .put (key , newV );
562
+ }
563
+ } while ((key = p .nextFieldName ()) != null );
564
+ return m ;
565
+ }
566
+
458
567
/*
459
568
/**********************************************************
460
569
/* Separate "vanilla" implementation for common case of
@@ -585,6 +694,9 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt, Object into
585
694
throws IOException
586
695
{
587
696
switch (p .getCurrentTokenId ()) {
697
+ case JsonTokenId .ID_END_OBJECT :
698
+ case JsonTokenId .ID_END_ARRAY :
699
+ return intoValue ;
588
700
case JsonTokenId .ID_START_OBJECT :
589
701
{
590
702
JsonToken t = p .nextToken (); // to get to FIELD_NAME or END_OBJECT
@@ -594,7 +706,24 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt, Object into
594
706
}
595
707
case JsonTokenId .ID_FIELD_NAME :
596
708
if (intoValue instanceof Map <?,?>) {
597
- return mapObject (p , ctxt , (Map <Object ,Object >) intoValue );
709
+ Map <Object ,Object > m = (Map <Object ,Object >) intoValue ;
710
+ // NOTE: we are guaranteed to point to FIELD_NAME
711
+ String key = p .getCurrentName ();
712
+ do {
713
+ p .nextToken ();
714
+ // and possibly recursive merge here
715
+ Object old = m .get (key );
716
+ Object newV ;
717
+ if (old != null ) {
718
+ newV = deserialize (p , ctxt , old );
719
+ } else {
720
+ newV = deserialize (p , ctxt );
721
+ }
722
+ if (newV != old ) {
723
+ m .put (key , newV );
724
+ }
725
+ } while ((key = p .nextFieldName ()) != null );
726
+ return intoValue ;
598
727
}
599
728
break ;
600
729
case JsonTokenId .ID_START_ARRAY :
@@ -606,7 +735,12 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt, Object into
606
735
}
607
736
608
737
if (intoValue instanceof Collection <?>) {
609
- return mapArray (p , ctxt , (Collection <Object >) intoValue );
738
+ Collection <Object > c = (Collection <Object >) intoValue ;
739
+ // NOTE: merge for arrays/Collections means append, can't merge contents
740
+ do {
741
+ c .add (deserialize (p , ctxt ));
742
+ } while (p .nextToken () != JsonToken .END_ARRAY );
743
+ return intoValue ;
610
744
}
611
745
// 21-Apr-2017, tatu: Should we try to support merging of Object[] values too?
612
746
// ... maybe future improvement
@@ -669,15 +803,6 @@ protected Object[] mapArrayToArray(JsonParser p, DeserializationContext ctxt) th
669
803
} while (p .nextToken () != JsonToken .END_ARRAY );
670
804
return buffer .completeAndClearBuffer (values , ptr );
671
805
}
672
-
673
- protected Object mapArray (JsonParser p , DeserializationContext ctxt ,
674
- Collection <Object > result ) throws IOException
675
- {
676
- do {
677
- result .add (deserialize (p , ctxt ));
678
- } while (p .nextToken () != JsonToken .END_ARRAY );
679
- return result ;
680
- }
681
806
682
807
/**
683
808
* Method called to map a JSON Object into a Java value.
@@ -715,17 +840,5 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
715
840
} while ((key = p .nextFieldName ()) != null );
716
841
return result ;
717
842
}
718
-
719
- protected Object mapObject (JsonParser p , DeserializationContext ctxt ,
720
- Map <Object ,Object > result ) throws IOException
721
- {
722
- // NOTE: we are guaranteed to point to FIELD_NAME
723
- String key = p .getCurrentName ();
724
- do {
725
- p .nextToken ();
726
- result .put (key , deserialize (p , ctxt ));
727
- } while ((key = p .nextFieldName ()) != null );
728
- return result ;
729
- }
730
843
}
731
844
}
0 commit comments