@@ -43,6 +43,12 @@ public abstract class StdDeserializer<T>
43
43
protected final static int F_MASK_INT_COERCIONS =
44
44
DeserializationFeature .USE_BIG_INTEGER_FOR_INTS .getMask ()
45
45
| DeserializationFeature .USE_LONG_FOR_INTS .getMask ();
46
+
47
+ // @since 2.9
48
+ protected final static int F_MASK_ACCEPT_ARRAYS =
49
+ DeserializationFeature .UNWRAP_SINGLE_VALUE_ARRAYS .getMask () |
50
+ DeserializationFeature .ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT .getMask ();
51
+
46
52
47
53
/**
48
54
* Type of values this deserializer handles: sometimes
@@ -128,7 +134,7 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
128
134
TypeDeserializer typeDeserializer ) throws IOException {
129
135
return typeDeserializer .deserializeTypedFromAny (p , ctxt );
130
136
}
131
-
137
+
132
138
/*
133
139
/**********************************************************
134
140
/* Helper methods for sub-classes, parsing: while mostly
@@ -455,26 +461,42 @@ protected final double _parseDoublePrimitive(DeserializationContext ctxt, String
455
461
protected java .util .Date _parseDate (JsonParser p , DeserializationContext ctxt )
456
462
throws IOException
457
463
{
458
- JsonToken t = p .getCurrentToken ();
459
- if (t == JsonToken .VALUE_NUMBER_INT ) {
464
+ switch (p .getCurrentTokenId ()) {
465
+ case JsonTokenId .ID_STRING :
466
+ return _parseDate (p .getText ().trim (), ctxt );
467
+ case JsonTokenId .ID_NUMBER_INT :
460
468
return new java .util .Date (p .getLongValue ());
461
- }
462
- if (t == JsonToken .VALUE_NULL ) {
469
+ case JsonTokenId .ID_NULL :
463
470
return (java .util .Date ) getNullValue (ctxt );
464
- }
465
- if (t == JsonToken .VALUE_STRING ) {
466
- return _parseDate (p .getText ().trim (), ctxt );
467
- }
468
- // [databind#381]
469
- if (t == JsonToken .START_ARRAY && ctxt .isEnabled (DeserializationFeature .UNWRAP_SINGLE_VALUE_ARRAYS )) {
470
- p .nextToken ();
471
- final Date parsed = _parseDate (p , ctxt );
472
- _verifyEndArrayForSingle (p , ctxt );
473
- return parsed ;
471
+ case JsonTokenId .ID_START_ARRAY :
472
+ return _parseDateFromArray (p , ctxt );
474
473
}
475
474
return (java .util .Date ) ctxt .handleUnexpectedToken (_valueClass , p );
476
475
}
477
476
477
+ // @since 2.9
478
+ protected java .util .Date _parseDateFromArray (JsonParser p , DeserializationContext ctxt )
479
+ throws IOException
480
+ {
481
+ JsonToken t ;
482
+ if (ctxt .hasSomeOfFeatures (F_MASK_ACCEPT_ARRAYS )) {
483
+ t = p .nextToken ();
484
+ if (t == JsonToken .END_ARRAY ) {
485
+ if (ctxt .isEnabled (DeserializationFeature .ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT )) {
486
+ return (java .util .Date ) getNullValue (ctxt );
487
+ }
488
+ }
489
+ if (ctxt .isEnabled (DeserializationFeature .UNWRAP_SINGLE_VALUE_ARRAYS )) {
490
+ final Date parsed = _parseDate (p , ctxt );
491
+ _verifyEndArrayForSingle (p , ctxt );
492
+ return parsed ;
493
+ }
494
+ } else {
495
+ t = p .getCurrentToken ();
496
+ }
497
+ return (java .util .Date ) ctxt .handleUnexpectedToken (_valueClass , t , p , null );
498
+ }
499
+
478
500
/**
479
501
* @since 2.8
480
502
*/
@@ -594,6 +616,78 @@ protected final boolean _isPosInf(String text) {
594
616
595
617
protected final boolean _isNaN (String text ) { return "NaN" .equals (text ); }
596
618
619
+ /*
620
+ /**********************************************************
621
+ /* Helper methods for sub-classes regarding decoding from
622
+ /* alternate representations
623
+ /**********************************************************
624
+ */
625
+
626
+ /**
627
+ * Helper method that allows easy support for array-related {@link DeserializationFeature}s
628
+ * `ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT` and `UNWRAP_SINGLE_VALUE_ARRAYS`: checks for either
629
+ * empty array, or single-value array-wrapped value (respectively), and either reports
630
+ * an exception (if no match, or feature(s) not enabled), or returns appropriate
631
+ * result value.
632
+ *<p>
633
+ * This method should NOT be called if Array representation is explicitly supported
634
+ * for type: it should only be called in case it is otherwise unrecognized.
635
+ *<p>
636
+ * NOTE: in case of unwrapped single element, will handle actual decoding
637
+ * by calling {@link #_deserializeWrappedValue}, which by default calls
638
+ * {@link #deserialize(JsonParser, DeserializationContext)}.
639
+ *
640
+ * @since 2.9
641
+ */
642
+ protected T _deserializeFromArray (JsonParser p , DeserializationContext ctxt ) throws IOException
643
+ {
644
+ JsonToken t ;
645
+ if (ctxt .hasSomeOfFeatures (F_MASK_ACCEPT_ARRAYS )) {
646
+ t = p .nextToken ();
647
+ if (t == JsonToken .END_ARRAY ) {
648
+ if (ctxt .isEnabled (DeserializationFeature .ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT )) {
649
+ return getNullValue (ctxt );
650
+ }
651
+ }
652
+ if (ctxt .isEnabled (DeserializationFeature .UNWRAP_SINGLE_VALUE_ARRAYS )) {
653
+ final T parsed = deserialize (p , ctxt );
654
+ if (p .nextToken () != JsonToken .END_ARRAY ) {
655
+ handleMissingEndArrayForSingle (p , ctxt );
656
+ }
657
+ return parsed ;
658
+ }
659
+ } else {
660
+ t = p .getCurrentToken ();
661
+ }
662
+ @ SuppressWarnings ("unchecked" )
663
+ T result = (T ) ctxt .handleUnexpectedToken (_valueClass , t , p , null );
664
+ return result ;
665
+ }
666
+
667
+ /**
668
+ * Helper called to support {@link DeserializationFeature#UNWRAP_SINGLE_VALUE_ARRAYS}:
669
+ * default implementation simply calls
670
+ * {@link #deserialize(JsonParser, DeserializationContext)},
671
+ * but handling may be overridden.
672
+ *
673
+ * @since 2.9
674
+ */
675
+ protected T _deserializeWrappedValue (JsonParser p , DeserializationContext ctxt ) throws IOException
676
+ {
677
+ // 23-Mar-2017, tatu: Let's specifically block recursive resolution to avoid
678
+ // either supporting nested arrays, or to cause infinite looping.
679
+ if (p .hasToken (JsonToken .START_ARRAY )) {
680
+ String msg = String .format (
681
+ "Can not deserialize instance of %s out of %s token: nested Arrays not allowed with %s" ,
682
+ ClassUtil .nameOf (_valueClass ), JsonToken .START_ARRAY ,
683
+ "DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS" );
684
+ @ SuppressWarnings ("unchecked" )
685
+ T result = (T ) ctxt .handleUnexpectedToken (_valueClass , p .getCurrentToken (), p , msg );
686
+ return result ;
687
+ }
688
+ return (T ) deserialize (p , ctxt );
689
+ }
690
+
597
691
/*
598
692
/****************************************************
599
693
/* Helper methods for sub-classes, coercions
0 commit comments