• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.deser.std;
2 
3 import java.io.IOException;
4 import java.util.*;
5 
6 import com.fasterxml.jackson.annotation.JsonFormat;
7 import com.fasterxml.jackson.annotation.Nulls;
8 
9 import com.fasterxml.jackson.core.*;
10 import com.fasterxml.jackson.core.JsonParser.NumberType;
11 import com.fasterxml.jackson.core.exc.InputCoercionException;
12 import com.fasterxml.jackson.core.io.NumberInput;
13 
14 import com.fasterxml.jackson.databind.*;
15 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
16 import com.fasterxml.jackson.databind.cfg.CoercionAction;
17 import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
18 import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
19 import com.fasterxml.jackson.databind.deser.NullValueProvider;
20 import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
21 import com.fasterxml.jackson.databind.deser.ValueInstantiator;
22 import com.fasterxml.jackson.databind.deser.impl.NullsAsEmptyProvider;
23 import com.fasterxml.jackson.databind.deser.impl.NullsConstantProvider;
24 import com.fasterxml.jackson.databind.deser.impl.NullsFailProvider;
25 import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
26 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
27 import com.fasterxml.jackson.databind.type.LogicalType;
28 import com.fasterxml.jackson.databind.util.AccessPattern;
29 import com.fasterxml.jackson.databind.util.ClassUtil;
30 import com.fasterxml.jackson.databind.util.Converter;
31 
32 /**
33  * Base class for common deserializers. Contains shared
34  * base functionality for dealing with primitive values, such
35  * as (re)parsing from String.
36  */
37 public abstract class StdDeserializer<T>
38     extends JsonDeserializer<T>
39     implements java.io.Serializable,
40         ValueInstantiator.Gettable // since 2.12
41 {
42     private static final long serialVersionUID = 1L;
43 
44     /**
45      * Bitmask that covers {@link DeserializationFeature#USE_BIG_INTEGER_FOR_INTS}
46      * and {@link DeserializationFeature#USE_LONG_FOR_INTS}, used for more efficient
47      * cheks when coercing integral values for untyped deserialization.
48      *
49      * @since 2.6
50      */
51     protected final static int F_MASK_INT_COERCIONS =
52             DeserializationFeature.USE_BIG_INTEGER_FOR_INTS.getMask()
53             | DeserializationFeature.USE_LONG_FOR_INTS.getMask();
54 
55     @Deprecated // since 2.12
56     protected final static int F_MASK_ACCEPT_ARRAYS =
57             DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS.getMask() |
58             DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT.getMask();
59 
60     /**
61      * Type of values this deserializer handles: sometimes
62      * exact types, other time most specific supertype of
63      * types deserializer handles (which may be as generic
64      * as {@link Object} in some case)
65      */
66     final protected Class<?> _valueClass;
67 
68     final protected JavaType _valueType;
69 
StdDeserializer(Class<?> vc)70     protected StdDeserializer(Class<?> vc) {
71         _valueClass = vc;
72         _valueType = null;
73     }
74 
StdDeserializer(JavaType valueType)75     protected StdDeserializer(JavaType valueType) {
76         // 26-Sep-2017, tatu: [databind#1764] need to add null-check back until 3.x
77         _valueClass = (valueType == null) ? Object.class : valueType.getRawClass();
78         _valueType = valueType;
79     }
80 
81     /**
82      * Copy-constructor for sub-classes to use, most often when creating
83      * new instances for {@link com.fasterxml.jackson.databind.deser.ContextualDeserializer}.
84      *
85      * @since 2.5
86      */
StdDeserializer(StdDeserializer<?> src)87     protected StdDeserializer(StdDeserializer<?> src) {
88         _valueClass = src._valueClass;
89         _valueType = src._valueType;
90     }
91 
92     /*
93     /**********************************************************
94     /* Accessors
95     /**********************************************************
96      */
97 
98     @Override
handledType()99     public Class<?> handledType() { return _valueClass; }
100 
101     /*
102     /**********************************************************
103     /* Extended API
104     /**********************************************************
105      */
106 
107     /**
108      * @deprecated Since 2.3 use {@link #handledType} instead
109      */
110     @Deprecated
getValueClass()111     public final Class<?> getValueClass() { return _valueClass; }
112 
113     /**
114      * Exact structured type this deserializer handles, if known.
115      */
getValueType()116     public JavaType getValueType() { return _valueType; }
117 
118     /**
119      * Convenience method for getting handled type as {@link JavaType}, regardless
120      * of whether deserializer has one already resolved (and accessible via
121      * {@link #getValueType()}) or not: equivalent to:
122      *<pre>
123      *   if (getValueType() != null) {
124      *        return getValueType();
125      *   }
126      *   return ctxt.constructType(handledType());
127      *</pre>
128      *
129      * @since 2.10
130      */
getValueType(DeserializationContext ctxt)131     public JavaType getValueType(DeserializationContext ctxt) {
132         if (_valueType != null) {
133             return _valueType;
134         }
135         return ctxt.constructType(_valueClass);
136     }
137 
138     /**
139      * @since 2.12
140      */
141     @Override // for ValueInstantiator.Gettable
getValueInstantiator()142     public ValueInstantiator getValueInstantiator() { return null; }
143 
144     /**
145      * Method that can be called to determine if given deserializer is the default
146      * deserializer Jackson uses; as opposed to a custom deserializer installed by
147      * a module or calling application. Determination is done using
148      * {@link JacksonStdImpl} annotation on deserializer class.
149      */
isDefaultDeserializer(JsonDeserializer<?> deserializer)150     protected boolean isDefaultDeserializer(JsonDeserializer<?> deserializer) {
151         return ClassUtil.isJacksonStdImpl(deserializer);
152     }
153 
isDefaultKeyDeserializer(KeyDeserializer keyDeser)154     protected boolean isDefaultKeyDeserializer(KeyDeserializer keyDeser) {
155         return ClassUtil.isJacksonStdImpl(keyDeser);
156     }
157 
158     /*
159     /**********************************************************
160     /* Partial JsonDeserializer implementation
161     /**********************************************************
162      */
163 
164     /**
165      * Base implementation that does not assume specific type
166      * inclusion mechanism. Sub-classes are expected to override
167      * this method if they are to handle type information.
168      */
169     @Override
deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer)170     public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
171             TypeDeserializer typeDeserializer) throws IOException {
172         return typeDeserializer.deserializeTypedFromAny(p, ctxt);
173     }
174 
175     /*
176     /**********************************************************************
177     /* High-level handling of secondary input shapes (with possible coercion)
178     /**********************************************************************
179      */
180 
181     /**
182      * Helper method that allows easy support for array-related coercion features:
183      * checks for either empty array, or single-value array-wrapped value (if coercion
184      * enabled by {@code CoercionConfigs} (since 2.12), and either reports
185      * an exception (if no coercion allowed), or returns appropriate
186      * result value using coercion mechanism indicated.
187      *<p>
188      * This method should NOT be called if Array representation is explicitly supported
189      * for type: it should only be called in case it is otherwise unrecognized.
190      *<p>
191      * NOTE: in case of unwrapped single element, will handle actual decoding
192      * by calling {@link #_deserializeWrappedValue}, which by default calls
193      * {@link #deserialize(JsonParser, DeserializationContext)}.
194      *
195      * @since 2.9
196      */
197     @SuppressWarnings("unchecked")
_deserializeFromArray(JsonParser p, DeserializationContext ctxt)198     protected T _deserializeFromArray(JsonParser p, DeserializationContext ctxt) throws IOException
199     {
200         final CoercionAction act = _findCoercionFromEmptyArray(ctxt);
201         final boolean unwrap = ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
202 
203         if (unwrap || (act != CoercionAction.Fail)) {
204             JsonToken t = p.nextToken();
205             if (t == JsonToken.END_ARRAY) {
206                 switch (act) {
207                 case AsEmpty:
208                     return (T) getEmptyValue(ctxt);
209                 case AsNull:
210                 case TryConvert:
211                     return getNullValue(ctxt);
212                 default:
213                 }
214             } else if (unwrap) {
215                 final T parsed = _deserializeWrappedValue(p, ctxt);
216                 if (p.nextToken() != JsonToken.END_ARRAY) {
217                     handleMissingEndArrayForSingle(p, ctxt);
218                 }
219                 return parsed;
220             }
221         }
222         return (T) ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null);
223     }
224 
225     /**
226      * Helper method that may be used to support fallback for Empty String / Empty Array
227      * non-standard representations; usually for things serialized as JSON Objects.
228      *
229      * @since 2.5
230      *
231      * @deprecated Since 2.12
232      */
233     @SuppressWarnings("unchecked")
234     @Deprecated // since 2.12
_deserializeFromEmpty(JsonParser p, DeserializationContext ctxt)235     protected T _deserializeFromEmpty(JsonParser p, DeserializationContext ctxt)
236         throws IOException
237     {
238         if (p.hasToken(JsonToken.START_ARRAY)) {
239             if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) {
240                 JsonToken t = p.nextToken();
241                 if (t == JsonToken.END_ARRAY) {
242                     return null;
243                 }
244                 return (T) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
245             }
246         }
247         return (T) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
248     }
249 
250     /**
251      * Helper method to call in case deserializer does not support native automatic
252      * use of incoming String values, but there may be standard coercions to consider.
253      *
254      * @since 2.12
255      */
256     @SuppressWarnings("unchecked")
_deserializeFromString(JsonParser p, DeserializationContext ctxt)257     protected T _deserializeFromString(JsonParser p, DeserializationContext ctxt)
258             throws IOException
259     {
260         final ValueInstantiator inst = getValueInstantiator();
261         final Class<?> rawTargetType = handledType();
262         String value = p.getValueAsString();
263 
264         if ((inst != null) && inst.canCreateFromString()) {
265             return (T) inst.createFromString(ctxt, value);
266         }
267 
268         if (value.length() == 0) {
269             final CoercionAction act = ctxt.findCoercionAction(logicalType(), rawTargetType,
270                     CoercionInputShape.EmptyString);
271             return (T) _deserializeFromEmptyString(p, ctxt, act, rawTargetType,
272                     "empty String (\"\")");
273         }
274         if (_isBlank(value)) {
275             final CoercionAction act = ctxt.findCoercionFromBlankString(logicalType(), rawTargetType,
276                     CoercionAction.Fail);
277             return (T) _deserializeFromEmptyString(p, ctxt, act, rawTargetType,
278                     "blank String (all whitespace)");
279         }
280 
281         // 28-Sep-2011, tatu: Ok this is not clean at all; but since there are legacy
282         //   systems that expect conversions in some cases, let's just add a minimal
283         //   patch (note: same could conceivably be used for numbers too).
284         if (inst != null) {
285             value = value.trim(); // mostly to avoid problems wrt XML indentation
286             if (inst.canCreateFromInt()) {
287                 if (ctxt.findCoercionAction(LogicalType.Integer, Integer.class,
288                         CoercionInputShape.String) == CoercionAction.TryConvert) {
289                     return (T) inst.createFromInt(ctxt, _parseIntPrimitive(ctxt, value));
290                 }
291             }
292             if (inst.canCreateFromLong()) {
293                 if (ctxt.findCoercionAction(LogicalType.Integer, Long.class,
294                         CoercionInputShape.String) == CoercionAction.TryConvert) {
295                     return (T) inst.createFromLong(ctxt, _parseLongPrimitive(ctxt, value));
296                 }
297             }
298             if (inst.canCreateFromBoolean()) {
299                 // 29-May-2020, tatu: With 2.12 can and should use CoercionConfig so:
300                 if (ctxt.findCoercionAction(LogicalType.Boolean, Boolean.class,
301                         CoercionInputShape.String) == CoercionAction.TryConvert) {
302                     String str = value.trim();
303                     if ("true".equals(str)) {
304                         return (T) inst.createFromBoolean(ctxt, true);
305                     }
306                     if ("false".equals(str)) {
307                         return (T) inst.createFromBoolean(ctxt, false);
308                     }
309                 }
310             }
311         }
312         return (T) ctxt.handleMissingInstantiator(rawTargetType, inst, ctxt.getParser(),
313                 "no String-argument constructor/factory method to deserialize from String value ('%s')",
314                 value);
315     }
316 
_deserializeFromEmptyString(JsonParser p, DeserializationContext ctxt, CoercionAction act, Class<?> rawTargetType, String desc)317     protected Object _deserializeFromEmptyString(JsonParser p, DeserializationContext ctxt,
318             CoercionAction act, Class<?> rawTargetType, String desc) throws IOException
319     {
320         switch (act) {
321         case AsEmpty:
322             return getEmptyValue(ctxt);
323         case TryConvert:
324             // hmmmh... empty or null, typically? Assume "as null" for now
325         case AsNull:
326             return null;
327         case Fail:
328             break;
329         }
330         final ValueInstantiator inst = getValueInstantiator();
331 
332         // 03-Jun-2020, tatu: Should ideally call `handleUnexpectedToken()` instead, but
333         //    since this call was already made, use it.
334         return ctxt.handleMissingInstantiator(rawTargetType, inst, p,
335 "Cannot deserialize value of type %s from %s (no String-argument constructor/factory method; coercion not enabled)",
336                 ClassUtil.getTypeDescription(getValueType(ctxt)), desc);
337     }
338 
339     /**
340      * Helper called to support {@link DeserializationFeature#UNWRAP_SINGLE_VALUE_ARRAYS}:
341      * default implementation simply calls
342      * {@link #deserialize(JsonParser, DeserializationContext)},
343      * but handling may be overridden.
344      *
345      * @since 2.9
346      */
_deserializeWrappedValue(JsonParser p, DeserializationContext ctxt)347     protected T _deserializeWrappedValue(JsonParser p, DeserializationContext ctxt) throws IOException
348     {
349         // 23-Mar-2017, tatu: Let's specifically block recursive resolution to avoid
350         //   either supporting nested arrays, or to cause infinite looping.
351         if (p.hasToken(JsonToken.START_ARRAY)) {
352             String msg = String.format(
353 "Cannot deserialize instance of %s out of %s token: nested Arrays not allowed with %s",
354                     ClassUtil.nameOf(_valueClass), JsonToken.START_ARRAY,
355                     "DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS");
356             @SuppressWarnings("unchecked")
357             T result = (T) ctxt.handleUnexpectedToken(getValueType(ctxt), p.currentToken(), p, msg);
358             return result;
359         }
360         return (T) deserialize(p, ctxt);
361     }
362 
363     /*
364     /**********************************************************
365     /* Helper methods for sub-classes, parsing: while mostly
366     /* useful for numeric types, can be also useful for dealing
367     /* with things serialized as numbers (such as Dates).
368     /**********************************************************
369      */
370 
371     @Deprecated // since 2.12, use overloaded variant that does NOT take target type
_parseBooleanPrimitive(DeserializationContext ctxt, JsonParser p, Class<?> targetType)372     protected final boolean _parseBooleanPrimitive(DeserializationContext ctxt,
373             JsonParser p, Class<?> targetType) throws IOException {
374         return _parseBooleanPrimitive(p, ctxt);
375     }
376 
377     /**
378      * @param ctxt Deserialization context for accessing configuration
379      * @param p Underlying parser
380      * @param targetType Actual type that is being deserialized, typically
381      *    same as {@link #handledType}, and not necessarily {@code boolean}
382      *    (may be {@code boolean[]} or {@code AtomicBoolean} for example);
383      *    used for coercion config access
384      */
_parseBooleanPrimitive(JsonParser p, DeserializationContext ctxt)385     protected final boolean _parseBooleanPrimitive(JsonParser p, DeserializationContext ctxt)
386             throws IOException
387     {
388         String text;
389         switch (p.currentTokenId()) {
390         case JsonTokenId.ID_STRING:
391             text = p.getText();
392             break;
393         case JsonTokenId.ID_NUMBER_INT:
394             // may accept ints too, (0 == false, otherwise true)
395 
396             // call returns `null`, Boolean.TRUE or Boolean.FALSE so:
397             return _coerceBooleanFromInt(p, ctxt, Boolean.TYPE) == Boolean.TRUE;
398         case JsonTokenId.ID_TRUE: // usually caller should have handled but:
399             return true;
400         case JsonTokenId.ID_FALSE:
401             return false;
402         case JsonTokenId.ID_NULL: // null fine for non-primitive
403             _verifyNullForPrimitive(ctxt);
404             return false;
405         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
406         case JsonTokenId.ID_START_OBJECT:
407             text = ctxt.extractScalarFromObject(p, this, Boolean.TYPE);
408             break;
409         case JsonTokenId.ID_START_ARRAY:
410             // 12-Jun-2020, tatu: For some reason calling `_deserializeFromArray()` won't work so:
411             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
412                 p.nextToken();
413                 final boolean parsed = _parseBooleanPrimitive(p, ctxt);
414                 _verifyEndArrayForSingle(p, ctxt);
415                 return parsed;
416             }
417             // fall through
418         default:
419             return ((Boolean) ctxt.handleUnexpectedToken(Boolean.TYPE, p)).booleanValue();
420         }
421 
422         final CoercionAction act = _checkFromStringCoercion(ctxt, text,
423                 LogicalType.Boolean, Boolean.TYPE);
424         if (act == CoercionAction.AsNull) {
425             _verifyNullForPrimitive(ctxt);
426             return false;
427         }
428         if (act == CoercionAction.AsEmpty) {
429             return false;
430         }
431         text = text.trim();
432         final int len = text.length();
433 
434         // For [databind#1852] allow some case-insensitive matches (namely,
435         // true/True/TRUE, false/False/FALSE
436         if (len == 4) {
437             if (_isTrue(text)) {
438                 return true;
439             }
440         } else if (len == 5) {
441             if (_isFalse(text)) {
442                 return false;
443             }
444         }
445         if (_hasTextualNull(text)) {
446             _verifyNullForPrimitiveCoercion(ctxt, text);
447             return false;
448         }
449         Boolean b = (Boolean) ctxt.handleWeirdStringValue(Boolean.TYPE, text,
450                 "only \"true\"/\"True\"/\"TRUE\" or \"false\"/\"False\"/\"FALSE\" recognized");
451         return Boolean.TRUE.equals(b);
452     }
453 
454     // [databind#1852]
_isTrue(String text)455     protected boolean _isTrue(String text) {
456         char c = text.charAt(0);
457         if (c == 't') {
458             return "true".equals(text);
459         }
460         if (c == 'T') {
461             return "TRUE".equals(text) || "True".equals(text);
462         }
463         return false;
464     }
465 
_isFalse(String text)466     protected boolean _isFalse(String text) {
467         char c = text.charAt(0);
468         if (c == 'f') {
469             return "false".equals(text);
470         }
471         if (c == 'F') {
472             return "FALSE".equals(text) || "False".equals(text);
473         }
474         return false;
475     }
476 
477     /**
478      * Helper method called for cases where non-primitive, boolean-based value
479      * is to be deserialized: result of this method will be {@link java.lang.Boolean},
480      * although actual target type may be something different.
481      *<p>
482      * Note: does NOT dynamically access "empty value" or "null value" of deserializer
483      * since those values could be of type other than {@link java.lang.Boolean}.
484      * Caller may need to translate from 3 possible result types into appropriately
485      * matching output types.
486      *
487      * @param p Underlying parser
488      * @param ctxt Deserialization context for accessing configuration
489      * @param targetType Actual type that is being deserialized, may be
490      *    same as {@link #handledType} but could be {@code AtomicBoolean} for example.
491      *    Used for coercion config access.
492      *
493      * @since 2.12
494      */
_parseBoolean(JsonParser p, DeserializationContext ctxt, Class<?> targetType)495     protected final Boolean _parseBoolean(JsonParser p, DeserializationContext ctxt,
496             Class<?> targetType)
497         throws IOException
498     {
499         String text;
500         switch (p.currentTokenId()) {
501         case JsonTokenId.ID_STRING:
502             text = p.getText();
503             break;
504         case JsonTokenId.ID_NUMBER_INT:
505             // may accept ints too, (0 == false, otherwise true)
506             return _coerceBooleanFromInt(p, ctxt, targetType);
507         case JsonTokenId.ID_TRUE:
508             return true;
509         case JsonTokenId.ID_FALSE:
510             return false;
511         case JsonTokenId.ID_NULL: // null fine for non-primitive
512             return null;
513         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
514         case JsonTokenId.ID_START_OBJECT:
515             text = ctxt.extractScalarFromObject(p, this, targetType);
516             break;
517         case JsonTokenId.ID_START_ARRAY: // unwrapping / from-empty-array coercion?
518             return (Boolean) _deserializeFromArray(p, ctxt);
519         default:
520             return (Boolean) ctxt.handleUnexpectedToken(targetType, p);
521         }
522 
523         final CoercionAction act = _checkFromStringCoercion(ctxt, text,
524                 LogicalType.Boolean, targetType);
525         if (act == CoercionAction.AsNull) {
526             return null;
527         }
528         if (act == CoercionAction.AsEmpty) {
529             return false;
530         }
531         text = text.trim();
532         final int len = text.length();
533 
534         // For [databind#1852] allow some case-insensitive matches (namely,
535         // true/True/TRUE, false/False/FALSE
536         if (len == 4) {
537             if (_isTrue(text)) {
538                 return true;
539             }
540         } else if (len == 5) {
541             if (_isFalse(text)) {
542                 return false;
543             }
544         }
545         if (_checkTextualNull(ctxt, text)) {
546             return null;
547         }
548         return (Boolean) ctxt.handleWeirdStringValue(targetType, text,
549                 "only \"true\" or \"false\" recognized");
550     }
551 
_parseBytePrimitive(JsonParser p, DeserializationContext ctxt)552     protected final byte _parseBytePrimitive(JsonParser p, DeserializationContext ctxt)
553         throws IOException
554     {
555         String text;
556         switch (p.currentTokenId()) {
557         case JsonTokenId.ID_STRING:
558             text = p.getText();
559             break;
560         case JsonTokenId.ID_NUMBER_FLOAT:
561             CoercionAction act = _checkFloatToIntCoercion(p, ctxt, Byte.TYPE);
562             if (act == CoercionAction.AsNull) {
563                 return (byte) 0;
564             }
565             if (act == CoercionAction.AsEmpty) {
566                 return (byte) 0;
567             }
568             return p.getByteValue();
569         case JsonTokenId.ID_NUMBER_INT:
570             return p.getByteValue();
571         case JsonTokenId.ID_NULL:
572             _verifyNullForPrimitive(ctxt);
573             return (byte) 0;
574         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
575         case JsonTokenId.ID_START_OBJECT:
576             text = ctxt.extractScalarFromObject(p, this, Byte.TYPE);
577             break;
578         case JsonTokenId.ID_START_ARRAY: // unwrapping / from-empty-array coercion?
579             // 12-Jun-2020, tatu: For some reason calling `_deserializeFromArray()` won't work so:
580             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
581                 p.nextToken();
582                 final byte parsed = _parseBytePrimitive(p, ctxt);
583                 _verifyEndArrayForSingle(p, ctxt);
584                 return parsed;
585             }
586             // fall through
587         default:
588             return ((Byte) ctxt.handleUnexpectedToken(ctxt.constructType(Byte.TYPE), p)).byteValue();
589         }
590 
591         // Coercion from String
592         CoercionAction act = _checkFromStringCoercion(ctxt, text,
593                 LogicalType.Integer, Byte.TYPE);
594         if (act == CoercionAction.AsNull) {
595             return (byte) 0; // no need to check as does not come from `null`, explicit coercion
596         }
597         if (act == CoercionAction.AsEmpty) {
598             return (byte) 0;
599         }
600         text = text.trim();
601         if (_hasTextualNull(text)) {
602             _verifyNullForPrimitiveCoercion(ctxt, text);
603             return (byte) 0;
604         }
605         int value;
606         try {
607             value = NumberInput.parseInt(text);
608         } catch (IllegalArgumentException iae) {
609             return (Byte) ctxt.handleWeirdStringValue(_valueClass, text,
610                     "not a valid `byte` value");
611         }
612         // So far so good: but does it fit? Allow both -128 / 255 range (inclusive)
613         if (_byteOverflow(value)) {
614             return (Byte) ctxt.handleWeirdStringValue(_valueClass, text,
615                     "overflow, value cannot be represented as 8-bit value");
616         }
617         return (byte) value;
618     }
619 
_parseShortPrimitive(JsonParser p, DeserializationContext ctxt)620     protected final short _parseShortPrimitive(JsonParser p, DeserializationContext ctxt)
621         throws IOException
622     {
623         String text;
624         switch (p.currentTokenId()) {
625         case JsonTokenId.ID_STRING:
626             text = p.getText();
627             break;
628         case JsonTokenId.ID_NUMBER_FLOAT:
629             CoercionAction act = _checkFloatToIntCoercion(p, ctxt, Short.TYPE);
630             if (act == CoercionAction.AsNull) {
631                 return (short) 0;
632             }
633             if (act == CoercionAction.AsEmpty) {
634                 return (short) 0;
635             }
636             return p.getShortValue();
637         case JsonTokenId.ID_NUMBER_INT:
638             return p.getShortValue();
639         case JsonTokenId.ID_NULL:
640             _verifyNullForPrimitive(ctxt);
641             return (short) 0;
642         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
643         case JsonTokenId.ID_START_OBJECT:
644             text = ctxt.extractScalarFromObject(p, this, Short.TYPE);
645             break;
646         case JsonTokenId.ID_START_ARRAY:
647             // 12-Jun-2020, tatu: For some reason calling `_deserializeFromArray()` won't work so:
648             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
649                 p.nextToken();
650                 final short parsed = _parseShortPrimitive(p, ctxt);
651                 _verifyEndArrayForSingle(p, ctxt);
652                 return parsed;
653             }
654             // fall through to fail
655         default:
656             return ((Short) ctxt.handleUnexpectedToken(ctxt.constructType(Short.TYPE), p)).shortValue();
657         }
658 
659         CoercionAction act = _checkFromStringCoercion(ctxt, text,
660                 LogicalType.Integer, Short.TYPE);
661         if (act == CoercionAction.AsNull) {
662             return (short) 0; // no need to check as does not come from `null`, explicit coercion
663         }
664         if (act == CoercionAction.AsEmpty) {
665             return (short) 0;
666         }
667         text = text.trim();
668         if (_hasTextualNull(text)) {
669             _verifyNullForPrimitiveCoercion(ctxt, text);
670             return (short) 0;
671         }
672         int value;
673         try {
674             value = NumberInput.parseInt(text);
675         } catch (IllegalArgumentException iae) {
676             return (Short) ctxt.handleWeirdStringValue(Short.TYPE, text,
677                     "not a valid `short` value");
678         }
679         if (_shortOverflow(value)) {
680             return (Short) ctxt.handleWeirdStringValue(Short.TYPE, text,
681                     "overflow, value cannot be represented as 16-bit value");
682         }
683         return (short) value;
684     }
685 
_parseIntPrimitive(JsonParser p, DeserializationContext ctxt)686     protected final int _parseIntPrimitive(JsonParser p, DeserializationContext ctxt)
687         throws IOException
688     {
689         String text;
690         switch (p.currentTokenId()) {
691         case JsonTokenId.ID_STRING:
692             text = p.getText();
693             break;
694         case JsonTokenId.ID_NUMBER_FLOAT:
695             final CoercionAction act = _checkFloatToIntCoercion(p, ctxt, Integer.TYPE);
696             if (act == CoercionAction.AsNull) {
697                 return 0;
698             }
699             if (act == CoercionAction.AsEmpty) {
700                 return 0;
701             }
702             return p.getValueAsInt();
703         case JsonTokenId.ID_NUMBER_INT:
704             return p.getIntValue();
705         case JsonTokenId.ID_NULL:
706             _verifyNullForPrimitive(ctxt);
707             return 0;
708         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
709         case JsonTokenId.ID_START_OBJECT:
710             text = ctxt.extractScalarFromObject(p, this, Integer.TYPE);
711             break;
712         case JsonTokenId.ID_START_ARRAY:
713             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
714                 p.nextToken();
715                 final int parsed = _parseIntPrimitive(p, ctxt);
716                 _verifyEndArrayForSingle(p, ctxt);
717                 return parsed;
718             }
719             // fall through to fail
720         default:
721             return ((Number) ctxt.handleUnexpectedToken(Integer.TYPE, p)).intValue();
722         }
723 
724         final CoercionAction act = _checkFromStringCoercion(ctxt, text,
725                 LogicalType.Integer, Integer.TYPE);
726         if (act == CoercionAction.AsNull) {
727             return 0; // no need to check as does not come from `null`, explicit coercion
728         }
729         if (act == CoercionAction.AsEmpty) {
730             return 0;
731         }
732         text = text.trim();
733         if (_hasTextualNull(text)) {
734             _verifyNullForPrimitiveCoercion(ctxt, text);
735             return 0;
736         }
737         return _parseIntPrimitive(ctxt, text);
738     }
739 
740     /**
741      * @since 2.9
742      */
_parseIntPrimitive(DeserializationContext ctxt, String text)743     protected final int _parseIntPrimitive(DeserializationContext ctxt, String text) throws IOException
744     {
745         try {
746             if (text.length() > 9) {
747                 long l = Long.parseLong(text);
748                 if (_intOverflow(l)) {
749                     Number v = (Number) ctxt.handleWeirdStringValue(Integer.TYPE, text,
750                         "Overflow: numeric value (%s) out of range of int (%d -%d)",
751                         text, Integer.MIN_VALUE, Integer.MAX_VALUE);
752                     return _nonNullNumber(v).intValue();
753                 }
754                 return (int) l;
755             }
756             return NumberInput.parseInt(text);
757         } catch (IllegalArgumentException iae) {
758             Number v = (Number) ctxt.handleWeirdStringValue(Integer.TYPE, text,
759                     "not a valid `int` value");
760             return _nonNullNumber(v).intValue();
761         }
762     }
763 
_parseLongPrimitive(JsonParser p, DeserializationContext ctxt)764     protected final long _parseLongPrimitive(JsonParser p, DeserializationContext ctxt)
765             throws IOException
766     {
767         String text;
768         switch (p.currentTokenId()) {
769         case JsonTokenId.ID_STRING:
770             text = p.getText();
771             break;
772         case JsonTokenId.ID_NUMBER_FLOAT:
773             final CoercionAction act = _checkFloatToIntCoercion(p, ctxt, Long.TYPE);
774             if (act == CoercionAction.AsNull) {
775                 return 0L;
776             }
777             if (act == CoercionAction.AsEmpty) {
778                 return 0L;
779             }
780             return p.getValueAsLong();
781         case JsonTokenId.ID_NUMBER_INT:
782             return p.getLongValue();
783         case JsonTokenId.ID_NULL:
784             _verifyNullForPrimitive(ctxt);
785             return 0L;
786         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
787         case JsonTokenId.ID_START_OBJECT:
788             text = ctxt.extractScalarFromObject(p, this, Long.TYPE);
789             break;
790         case JsonTokenId.ID_START_ARRAY:
791             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
792                 p.nextToken();
793                 final long parsed = _parseLongPrimitive(p, ctxt);
794                 _verifyEndArrayForSingle(p, ctxt);
795                 return parsed;
796             }
797             // fall through
798         default:
799             return ((Number) ctxt.handleUnexpectedToken(Long.TYPE, p)).longValue();
800         }
801 
802         final CoercionAction act = _checkFromStringCoercion(ctxt, text,
803                 LogicalType.Integer, Long.TYPE);
804         if (act == CoercionAction.AsNull) {
805             return 0L; // no need to check as does not come from `null`, explicit coercion
806         }
807         if (act == CoercionAction.AsEmpty) {
808             return 0L;
809         }
810         text = text.trim();
811         if (_hasTextualNull(text)) {
812             _verifyNullForPrimitiveCoercion(ctxt, text);
813             return 0L;
814         }
815         return _parseLongPrimitive(ctxt, text);
816     }
817 
818     /**
819      * @since 2.9
820      */
_parseLongPrimitive(DeserializationContext ctxt, String text)821     protected final long _parseLongPrimitive(DeserializationContext ctxt, String text) throws IOException
822     {
823         try {
824             return NumberInput.parseLong(text);
825         } catch (IllegalArgumentException iae) { }
826         {
827             Number v = (Number) ctxt.handleWeirdStringValue(Long.TYPE, text,
828                     "not a valid `long` value");
829             return _nonNullNumber(v).longValue();
830         }
831     }
832 
_parseFloatPrimitive(JsonParser p, DeserializationContext ctxt)833     protected final float _parseFloatPrimitive(JsonParser p, DeserializationContext ctxt)
834         throws IOException
835     {
836         String text;
837         switch (p.currentTokenId()) {
838         case JsonTokenId.ID_STRING:
839             text = p.getText();
840             break;
841         case JsonTokenId.ID_NUMBER_INT:
842         case JsonTokenId.ID_NUMBER_FLOAT:
843             return p.getFloatValue();
844         case JsonTokenId.ID_NULL:
845             _verifyNullForPrimitive(ctxt);
846             return 0f;
847         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
848         case JsonTokenId.ID_START_OBJECT:
849             text = ctxt.extractScalarFromObject(p, this, Float.TYPE);
850             break;
851         case JsonTokenId.ID_START_ARRAY:
852             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
853                 p.nextToken();
854                 final float parsed = _parseFloatPrimitive(p, ctxt);
855                 _verifyEndArrayForSingle(p, ctxt);
856                 return parsed;
857             }
858             // fall through
859         default:
860             return ((Number) ctxt.handleUnexpectedToken(Float.TYPE, p)).floatValue();
861         }
862 
863         final CoercionAction act = _checkFromStringCoercion(ctxt, text,
864                 LogicalType.Integer, Float.TYPE);
865         if (act == CoercionAction.AsNull) {
866             return  0.0f; // no need to check as does not come from `null`, explicit coercion
867         }
868         if (act == CoercionAction.AsEmpty) {
869             return  0.0f;
870         }
871         text = text.trim();
872         if (_hasTextualNull(text)) {
873             _verifyNullForPrimitiveCoercion(ctxt, text);
874             return  0.0f;
875         }
876         return _parseFloatPrimitive(ctxt, text);
877 }
878 
879     /**
880      * @since 2.9
881      */
_parseFloatPrimitive(DeserializationContext ctxt, String text)882     protected final float _parseFloatPrimitive(DeserializationContext ctxt, String text)
883         throws IOException
884     {
885         switch (text.charAt(0)) {
886         case 'I':
887             if (_isPosInf(text)) {
888                 return Float.POSITIVE_INFINITY;
889             }
890             break;
891         case 'N':
892             if (_isNaN(text)) { return Float.NaN; }
893             break;
894         case '-':
895             if (_isNegInf(text)) {
896                 return Float.NEGATIVE_INFINITY;
897             }
898             break;
899         }
900         try {
901             return Float.parseFloat(text);
902         } catch (IllegalArgumentException iae) { }
903         Number v = (Number) ctxt.handleWeirdStringValue(Float.TYPE, text,
904                 "not a valid `float` value");
905         return _nonNullNumber(v).floatValue();
906     }
907 
_parseDoublePrimitive(JsonParser p, DeserializationContext ctxt)908     protected final double _parseDoublePrimitive(JsonParser p, DeserializationContext ctxt)
909         throws IOException
910     {
911         String text;
912         switch (p.currentTokenId()) {
913         case JsonTokenId.ID_STRING:
914             text = p.getText();
915             break;
916         case JsonTokenId.ID_NUMBER_INT:
917         case JsonTokenId.ID_NUMBER_FLOAT:
918             return p.getDoubleValue();
919         case JsonTokenId.ID_NULL:
920             _verifyNullForPrimitive(ctxt);
921             return 0.0;
922         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
923         case JsonTokenId.ID_START_OBJECT:
924             text = ctxt.extractScalarFromObject(p, this, Double.TYPE);
925             break;
926         case JsonTokenId.ID_START_ARRAY:
927             if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
928                 p.nextToken();
929                 final double parsed = _parseDoublePrimitive(p, ctxt);
930                 _verifyEndArrayForSingle(p, ctxt);
931                 return parsed;
932             }
933             // fall through
934         default:
935             return ((Number) ctxt.handleUnexpectedToken(Double.TYPE, p)).doubleValue();
936         }
937 
938         final CoercionAction act = _checkFromStringCoercion(ctxt, text,
939                 LogicalType.Integer, Double.TYPE);
940         if (act == CoercionAction.AsNull) {
941             return  0.0; // no need to check as does not come from `null`, explicit coercion
942         }
943         if (act == CoercionAction.AsEmpty) {
944             return  0.0;
945         }
946         text = text.trim();
947         if (_hasTextualNull(text)) {
948             _verifyNullForPrimitiveCoercion(ctxt, text);
949             return  0.0;
950         }
951         return _parseDoublePrimitive(ctxt, text);
952     }
953 
954     /**
955      * @since 2.9
956      */
_parseDoublePrimitive(DeserializationContext ctxt, String text)957     protected final double _parseDoublePrimitive(DeserializationContext ctxt, String text)
958         throws IOException
959     {
960         switch (text.charAt(0)) {
961         case 'I':
962             if (_isPosInf(text)) {
963                 return Double.POSITIVE_INFINITY;
964             }
965             break;
966         case 'N':
967             if (_isNaN(text)) {
968                 return Double.NaN;
969             }
970             break;
971         case '-':
972             if (_isNegInf(text)) {
973                 return Double.NEGATIVE_INFINITY;
974             }
975             break;
976         }
977         try {
978             return _parseDouble(text);
979         } catch (IllegalArgumentException iae) { }
980         Number v = (Number) ctxt.handleWeirdStringValue(Double.TYPE, text,
981                 "not a valid `double` value (as String to convert)");
982         return _nonNullNumber(v).doubleValue();
983     }
984 
985     /**
986      * Helper method for encapsulating calls to low-level double value parsing; single place
987      * just because we need a work-around that must be applied to all calls.
988      */
_parseDouble(String numStr)989     protected final static double _parseDouble(String numStr) throws NumberFormatException
990     {
991         // avoid some nasty float representations... but should it be MIN_NORMAL or MIN_VALUE?
992         if (NumberInput.NASTY_SMALL_DOUBLE.equals(numStr)) {
993             return Double.MIN_NORMAL; // since 2.7; was MIN_VALUE prior
994         }
995         return Double.parseDouble(numStr);
996     }
997 
_parseDate(JsonParser p, DeserializationContext ctxt)998     protected java.util.Date _parseDate(JsonParser p, DeserializationContext ctxt)
999         throws IOException
1000     {
1001         String text;
1002         switch (p.currentTokenId()) {
1003         case JsonTokenId.ID_STRING:
1004             text = p.getText();
1005             break;
1006         case JsonTokenId.ID_NUMBER_INT:
1007             {
1008                 long ts;
1009                 try {
1010                     ts = p.getLongValue();
1011                 // 16-Jan-2019, tatu: 2.10 uses InputCoercionException, earlier JsonParseException
1012                 //     (but leave both until 3.0)
1013                 } catch (JsonParseException | InputCoercionException e) {
1014                     Number v = (Number) ctxt.handleWeirdNumberValue(_valueClass, p.getNumberValue(),
1015                             "not a valid 64-bit `long` for creating `java.util.Date`");
1016                     ts = v.longValue();
1017                 }
1018                 return new java.util.Date(ts);
1019             }
1020         case JsonTokenId.ID_NULL:
1021             return (java.util.Date) getNullValue(ctxt);
1022         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
1023         case JsonTokenId.ID_START_OBJECT:
1024             text = ctxt.extractScalarFromObject(p, this, _valueClass);
1025             break;
1026         case JsonTokenId.ID_START_ARRAY:
1027             return _parseDateFromArray(p, ctxt);
1028         default:
1029             return (java.util.Date) ctxt.handleUnexpectedToken(_valueClass, p);
1030         }
1031 
1032         return _parseDate(text.trim(), ctxt);
1033     }
1034 
1035     // @since 2.9
_parseDateFromArray(JsonParser p, DeserializationContext ctxt)1036     protected java.util.Date _parseDateFromArray(JsonParser p, DeserializationContext ctxt)
1037             throws IOException
1038     {
1039         final CoercionAction act = _findCoercionFromEmptyArray(ctxt);
1040         final boolean unwrap = ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
1041 
1042         if (unwrap || (act != CoercionAction.Fail)) {
1043             JsonToken t = p.nextToken();
1044             if (t == JsonToken.END_ARRAY) {
1045                 switch (act) {
1046                 case AsEmpty:
1047                     return (java.util.Date) getEmptyValue(ctxt);
1048                 case AsNull:
1049                 case TryConvert:
1050                     return (java.util.Date) getNullValue(ctxt);
1051                 default:
1052                 }
1053             } else if (unwrap) {
1054                 final Date parsed = _parseDate(p, ctxt);
1055                 _verifyEndArrayForSingle(p, ctxt);
1056                 return parsed;
1057             }
1058         }
1059         return (java.util.Date) ctxt.handleUnexpectedToken(_valueClass, JsonToken.START_ARRAY, p, null);
1060     }
1061 
1062     /**
1063      * @since 2.8
1064      */
_parseDate(String value, DeserializationContext ctxt)1065     protected java.util.Date _parseDate(String value, DeserializationContext ctxt)
1066         throws IOException
1067     {
1068         try {
1069             // Take empty Strings to mean 'empty' Value, usually 'null':
1070             if (value.length() == 0) {
1071                 final CoercionAction act = _checkFromStringCoercion(ctxt, value);
1072                 switch (act) { // note: Fail handled above
1073                 case AsEmpty:
1074                     return new java.util.Date(0L);
1075                 case AsNull:
1076                 case TryConvert:
1077                 default:
1078                 }
1079                 return null;
1080             }
1081             // 10-Jun-2020, tatu: Legacy handling from pre-2.12... should we still have it?
1082             if (_hasTextualNull(value)) {
1083                 return null;
1084             }
1085             return ctxt.parseDate(value);
1086         } catch (IllegalArgumentException iae) {
1087             return (java.util.Date) ctxt.handleWeirdStringValue(_valueClass, value,
1088                     "not a valid representation (error: %s)",
1089                     ClassUtil.exceptionMessage(iae));
1090         }
1091     }
1092 
1093     /**
1094      * Helper method used for accessing String value, if possible, doing
1095      * necessary conversion or throwing exception as necessary.
1096      *
1097      * @since 2.1
1098      */
_parseString(JsonParser p, DeserializationContext ctxt)1099     protected final String _parseString(JsonParser p, DeserializationContext ctxt) throws IOException
1100     {
1101         if (p.hasToken(JsonToken.VALUE_STRING)) {
1102             return p.getText();
1103         }
1104         // 07-Nov-2019, tatu: [databind#2535] Need to support byte[]->Base64 same as `StringDeserializer`
1105         if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
1106             Object ob = p.getEmbeddedObject();
1107             if (ob instanceof byte[]) {
1108                 return ctxt.getBase64Variant().encode((byte[]) ob, false);
1109             }
1110             if (ob == null) {
1111                 return null;
1112             }
1113             // otherwise, try conversion using toString()...
1114             return ob.toString();
1115         }
1116         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
1117         if (p.hasToken(JsonToken.START_OBJECT)) {
1118             return ctxt.extractScalarFromObject(p, this, _valueClass);
1119         }
1120 
1121         String value = p.getValueAsString();
1122         if (value != null) {
1123             return value;
1124         }
1125         return (String) ctxt.handleUnexpectedToken(String.class, p);
1126     }
1127 
1128     /**
1129      * Helper method called to determine if we are seeing String value of
1130      * "null", and, further, that it should be coerced to null just like
1131      * null token.
1132      *
1133      * @since 2.3
1134      */
_hasTextualNull(String value)1135     protected boolean _hasTextualNull(String value) {
1136         return "null".equals(value);
1137     }
1138 
_isNegInf(String text)1139     protected final boolean _isNegInf(String text) {
1140         return "-Infinity".equals(text) || "-INF".equals(text);
1141     }
1142 
_isPosInf(String text)1143     protected final boolean _isPosInf(String text) {
1144         return "Infinity".equals(text) || "INF".equals(text);
1145     }
1146 
_isNaN(String text)1147     protected final boolean _isNaN(String text) { return "NaN".equals(text); }
1148 
1149     // @since 2.12
_isBlank(String text)1150     protected final static boolean _isBlank(String text)
1151     {
1152         final int len = text.length();
1153         for (int i = 0; i < len; ++i) {
1154             if (text.charAt(i) > 0x0020) {
1155                 return false;
1156             }
1157         }
1158         return true;
1159     }
1160 
1161     /*
1162     /****************************************************
1163     /* Helper methods for sub-classes, new (2.12+)
1164     /****************************************************
1165      */
1166 
1167     /**
1168      * @since 2.12
1169      */
_checkFromStringCoercion(DeserializationContext ctxt, String value)1170     protected CoercionAction _checkFromStringCoercion(DeserializationContext ctxt, String value)
1171         throws IOException
1172     {
1173         return _checkFromStringCoercion(ctxt, value, logicalType(), handledType());
1174     }
1175 
1176     /**
1177      * @since 2.12
1178      */
_checkFromStringCoercion(DeserializationContext ctxt, String value, LogicalType logicalType, Class<?> rawTargetType)1179     protected CoercionAction _checkFromStringCoercion(DeserializationContext ctxt, String value,
1180             LogicalType logicalType, Class<?> rawTargetType)
1181         throws IOException
1182     {
1183         final CoercionAction act;
1184 
1185         if (value.length() == 0) {
1186             act = ctxt.findCoercionAction(logicalType, rawTargetType,
1187                     CoercionInputShape.EmptyString);
1188             return _checkCoercionActionFail(ctxt, act, "empty String (\"\")");
1189         } else if (_isBlank(value)) {
1190             act = ctxt.findCoercionFromBlankString(logicalType, rawTargetType, CoercionAction.Fail);
1191             return _checkCoercionActionFail(ctxt, act, "blank String (all whitespace)");
1192         } else {
1193             act = ctxt.findCoercionAction(logicalType, rawTargetType, CoercionInputShape.String);
1194             if (act == CoercionAction.Fail) {
1195                 // since it MIGHT (but might not), create desc here, do not use helper
1196                 ctxt.reportInputMismatch(this,
1197 "Cannot coerce String value (\"%s\") to %s (but might if coercion using `CoercionConfig` was enabled)",
1198 value, _coercedTypeDesc());
1199             }
1200         }
1201         return act;
1202     }
1203 
1204     /**
1205      * @since 2.12
1206      */
_checkFloatToIntCoercion(JsonParser p, DeserializationContext ctxt, Class<?> rawTargetType)1207     protected CoercionAction _checkFloatToIntCoercion(JsonParser p, DeserializationContext ctxt,
1208             Class<?> rawTargetType)
1209         throws IOException
1210     {
1211         final CoercionAction act = ctxt.findCoercionAction(LogicalType.Integer,
1212                 rawTargetType, CoercionInputShape.Float);
1213         if (act == CoercionAction.Fail) {
1214             _checkCoercionActionFail(ctxt, act, "Floating-point value ("+p.getText()+")");
1215         }
1216         return act;
1217     }
1218 
1219     /**
1220      * @since 2.12
1221      */
_coerceBooleanFromInt(JsonParser p, DeserializationContext ctxt, Class<?> rawTargetType)1222     protected Boolean _coerceBooleanFromInt(JsonParser p, DeserializationContext ctxt,
1223             Class<?> rawTargetType)
1224         throws IOException
1225     {
1226         CoercionAction act = ctxt.findCoercionAction(LogicalType.Boolean, rawTargetType, CoercionInputShape.Integer);
1227         switch (act) {
1228         case Fail:
1229             _checkCoercionActionFail(ctxt, act, "Integer value ("+p.getText()+")");
1230             break;
1231         case AsNull:
1232             return null;
1233         case AsEmpty:
1234             return Boolean.FALSE;
1235         default:
1236         }
1237         // 13-Oct-2016, tatu: As per [databind#1324], need to be careful wrt
1238         //    degenerate case of huge integers, legal in JSON.
1239         //    Also note that number tokens can not have WS to trim:
1240         if (p.getNumberType() == NumberType.INT) {
1241             // but minor optimization for common case is possible:
1242             return p.getIntValue() != 0;
1243         }
1244         return !"0".equals(p.getText());
1245     }
1246 
_checkCoercionActionFail(DeserializationContext ctxt, CoercionAction act, String inputDesc)1247     protected CoercionAction _checkCoercionActionFail(DeserializationContext ctxt,
1248             CoercionAction act, String inputDesc) throws IOException
1249     {
1250         if (act == CoercionAction.Fail) {
1251             ctxt.reportInputMismatch(this,
1252 "Cannot coerce %s to %s (but could if coercion was enabled using `CoercionConfig`)",
1253 inputDesc, _coercedTypeDesc());
1254         }
1255         return act;
1256     }
1257 
1258     /**
1259      * Method called when otherwise unrecognized String value is encountered for
1260      * a non-primitive type: should see if it is String value {@code "null"}, and if so,
1261      * whether it is acceptable according to configuration or not
1262      *
1263      * @since 2.12
1264      */
_checkTextualNull(DeserializationContext ctxt, String text)1265     protected boolean _checkTextualNull(DeserializationContext ctxt, String text)
1266             throws JsonMappingException
1267     {
1268         if (_hasTextualNull(text)) {
1269             if (!ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS)) {
1270                 _reportFailedNullCoerce(ctxt, true,  MapperFeature.ALLOW_COERCION_OF_SCALARS, "String \"null\"");
1271             }
1272             return true;
1273         }
1274         return false;
1275     }
1276 
1277     /*
1278     /**********************************************************************
1279     /* Helper methods for sub-classes, coercions, older (pre-2.12), non-deprecated
1280     /**********************************************************************
1281      */
1282 
1283     /**
1284      * Helper method called in case where an integral number is encountered, but
1285      * config settings suggest that a coercion may be needed to "upgrade"
1286      * {@link java.lang.Number} into "bigger" type like {@link java.lang.Long} or
1287      * {@link java.math.BigInteger}
1288      *
1289      * @see DeserializationFeature#USE_BIG_INTEGER_FOR_INTS
1290      * @see DeserializationFeature#USE_LONG_FOR_INTS
1291      *
1292      * @since 2.6
1293      */
_coerceIntegral(JsonParser p, DeserializationContext ctxt)1294     protected Object _coerceIntegral(JsonParser p, DeserializationContext ctxt) throws IOException
1295     {
1296         int feats = ctxt.getDeserializationFeatures();
1297         if (DeserializationFeature.USE_BIG_INTEGER_FOR_INTS.enabledIn(feats)) {
1298             return p.getBigIntegerValue();
1299         }
1300         if (DeserializationFeature.USE_LONG_FOR_INTS.enabledIn(feats)) {
1301             return p.getLongValue();
1302         }
1303         return p.getNumberValue(); // should be optimal, whatever it is
1304     }
1305 
1306     /**
1307      * Method called to verify that {@code null} token from input is acceptable
1308      * for primitive (unboxed) target type. It should NOT be called if {@code null}
1309      * was received by other means (coerced due to configuration, or even from
1310      * optionally acceptable String {@code "null"} token).
1311      *
1312      * @since 2.9
1313      */
_verifyNullForPrimitive(DeserializationContext ctxt)1314     protected final void _verifyNullForPrimitive(DeserializationContext ctxt) throws JsonMappingException
1315     {
1316         if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
1317             ctxt.reportInputMismatch(this,
1318 "Cannot coerce `null` to %s (disable `DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES` to allow)",
1319                     _coercedTypeDesc());
1320         }
1321     }
1322 
1323     /**
1324      * Method called to verify that text value {@code "null"} from input is acceptable
1325      * for primitive (unboxed) target type. It should not be called if actual
1326      * {@code null} token was received, or if null is a result of coercion from
1327      * Some other input type.
1328      *
1329      * @since 2.9
1330      */
_verifyNullForPrimitiveCoercion(DeserializationContext ctxt, String str)1331     protected final void _verifyNullForPrimitiveCoercion(DeserializationContext ctxt, String str) throws JsonMappingException
1332     {
1333         Enum<?> feat;
1334         boolean enable;
1335 
1336         if (!ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS)) {
1337             feat = MapperFeature.ALLOW_COERCION_OF_SCALARS;
1338             enable = true;
1339         } else if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
1340             feat = DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES;
1341             enable = false;
1342         } else {
1343             return;
1344         }
1345         String strDesc = str.isEmpty() ? "empty String (\"\")" : String.format("String \"%s\"", str);
1346         _reportFailedNullCoerce(ctxt, enable, feat, strDesc);
1347     }
1348 
_reportFailedNullCoerce(DeserializationContext ctxt, boolean state, Enum<?> feature, String inputDesc)1349     protected void _reportFailedNullCoerce(DeserializationContext ctxt, boolean state, Enum<?> feature,
1350             String inputDesc) throws JsonMappingException
1351     {
1352         String enableDesc = state ? "enable" : "disable";
1353         ctxt.reportInputMismatch(this, "Cannot coerce %s to Null value as %s (%s `%s.%s` to allow)",
1354             inputDesc, _coercedTypeDesc(), enableDesc, feature.getClass().getSimpleName(), feature.name());
1355     }
1356 
1357     /**
1358      * Helper method called to get a description of type into which a scalar value coercion
1359      * is (most likely) being applied, to be used for constructing exception messages
1360      * on coerce failure.
1361      *
1362      * @return Message with backtick-enclosed name of type this deserializer supports
1363      *
1364      * @since 2.9
1365      */
_coercedTypeDesc()1366     protected String _coercedTypeDesc() {
1367         boolean structured;
1368         String typeDesc;
1369 
1370         JavaType t = getValueType();
1371         if ((t != null) && !t.isPrimitive()) {
1372             structured = (t.isContainerType() || t.isReferenceType());
1373             typeDesc = ClassUtil.getTypeDescription(t);
1374         } else {
1375             Class<?> cls = handledType();
1376             structured = cls.isArray() || Collection.class.isAssignableFrom(cls)
1377                 || Map.class.isAssignableFrom(cls);
1378             typeDesc = ClassUtil.getClassDescription(cls);
1379         }
1380         if (structured) {
1381             return "element of "+typeDesc;
1382         }
1383         return typeDesc+" value";
1384     }
1385 
1386     /*
1387     /**********************************************************************
1388     /* Helper methods for sub-classes, coercions, older (pre-2.12), deprecated
1389     /**********************************************************************
1390      */
1391 
1392     @Deprecated // since 2.12
_parseBooleanFromInt(JsonParser p, DeserializationContext ctxt)1393     protected boolean _parseBooleanFromInt(JsonParser p, DeserializationContext ctxt)
1394         throws IOException
1395     {
1396         // 13-Oct-2016, tatu: As per [databind#1324], need to be careful wrt
1397         //    degenerate case of huge integers, legal in JSON.
1398         //  ... this is, on the other hand, probably wrong/sub-optimal for non-JSON
1399         //  input. For now, no rea
1400         _verifyNumberForScalarCoercion(ctxt, p);
1401         // Anyway, note that since we know it's valid (JSON) integer, it can't have
1402         // extra whitespace to trim.
1403         return !"0".equals(p.getText());
1404     }
1405 
1406     /**
1407      * @deprecated Since 2.12 use {@link #_checkFromStringCoercion} instead
1408      */
1409     @Deprecated
_verifyStringForScalarCoercion(DeserializationContext ctxt, String str)1410     protected void _verifyStringForScalarCoercion(DeserializationContext ctxt, String str) throws JsonMappingException
1411     {
1412         MapperFeature feat = MapperFeature.ALLOW_COERCION_OF_SCALARS;
1413         if (!ctxt.isEnabled(feat)) {
1414             ctxt.reportInputMismatch(this, "Cannot coerce String \"%s\" to %s (enable `%s.%s` to allow)",
1415                 str, _coercedTypeDesc(), feat.getClass().getSimpleName(), feat.name());
1416         }
1417     }
1418 
1419     /**
1420      * Method called when JSON String with value "" (that is, zero length) is encountered.
1421      *
1422      * @deprecated Since 2.12
1423      */
1424     @Deprecated
_coerceEmptyString(DeserializationContext ctxt, boolean isPrimitive)1425     protected Object _coerceEmptyString(DeserializationContext ctxt, boolean isPrimitive) throws JsonMappingException
1426     {
1427         Enum<?> feat;
1428         boolean enable;
1429 
1430         if (!ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS)) {
1431             feat = MapperFeature.ALLOW_COERCION_OF_SCALARS;
1432             enable = true;
1433         } else if (isPrimitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
1434             feat = DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES;
1435             enable = false;
1436         } else {
1437             return getNullValue(ctxt);
1438         }
1439         _reportFailedNullCoerce(ctxt, enable, feat, "empty String (\"\")");
1440         return null;
1441     }
1442 
1443     @Deprecated // since 2.12
_failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt, String type)1444     protected void _failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt,
1445             String type) throws IOException
1446     {
1447         ctxt.reportInputMismatch(handledType(),
1448 "Cannot coerce a floating-point value ('%s') into %s (enable `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to allow)",
1449                 p.getValueAsString(), type);
1450     }
1451 
1452     @Deprecated // since 2.12
_verifyNullForScalarCoercion(DeserializationContext ctxt, String str)1453     protected final void _verifyNullForScalarCoercion(DeserializationContext ctxt, String str) throws JsonMappingException
1454     {
1455         if (!ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS)) {
1456             String strDesc = str.isEmpty() ? "empty String (\"\")" : String.format("String \"%s\"", str);
1457             _reportFailedNullCoerce(ctxt, true, MapperFeature.ALLOW_COERCION_OF_SCALARS, strDesc);
1458         }
1459     }
1460 
1461     @Deprecated // since 2.12
_verifyNumberForScalarCoercion(DeserializationContext ctxt, JsonParser p)1462     protected void _verifyNumberForScalarCoercion(DeserializationContext ctxt, JsonParser p) throws IOException
1463     {
1464         MapperFeature feat = MapperFeature.ALLOW_COERCION_OF_SCALARS;
1465         if (!ctxt.isEnabled(feat)) {
1466             // 31-Mar-2017, tatu: Since we don't know (or this deep, care) about exact type,
1467             //   access as a String: may require re-encoding by parser which should be fine
1468             String valueDesc = p.getText();
1469             ctxt.reportInputMismatch(this, "Cannot coerce Number (%s) to %s (enable `%s.%s` to allow)",
1470                 valueDesc, _coercedTypeDesc(), feat.getClass().getSimpleName(), feat.name());
1471         }
1472     }
1473 
1474     @Deprecated // since 2.12
_coerceNullToken(DeserializationContext ctxt, boolean isPrimitive)1475     protected Object _coerceNullToken(DeserializationContext ctxt, boolean isPrimitive) throws JsonMappingException
1476     {
1477         if (isPrimitive) {
1478             _verifyNullForPrimitive(ctxt);
1479         }
1480         return getNullValue(ctxt);
1481     }
1482 
1483     @Deprecated // since 2.12
_coerceTextualNull(DeserializationContext ctxt, boolean isPrimitive)1484     protected Object _coerceTextualNull(DeserializationContext ctxt, boolean isPrimitive) throws JsonMappingException {
1485         if (!ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS)) {
1486             _reportFailedNullCoerce(ctxt, true,  MapperFeature.ALLOW_COERCION_OF_SCALARS, "String \"null\"");
1487         }
1488         return getNullValue(ctxt);
1489     }
1490 
1491     @Deprecated // since 2.12
_isEmptyOrTextualNull(String value)1492     protected boolean _isEmptyOrTextualNull(String value) {
1493         return value.isEmpty() || "null".equals(value);
1494     }
1495 
1496     /*
1497     /****************************************************
1498     /* Helper methods for sub-classes, resolving dependencies
1499     /****************************************************
1500      */
1501 
1502     /**
1503      * Helper method used to locate deserializers for properties the
1504      * type this deserializer handles contains (usually for properties of
1505      * bean types)
1506      *
1507      * @param type Type of property to deserialize
1508      * @param property Actual property object (field, method, constuctor parameter) used
1509      *     for passing deserialized values; provided so deserializer can be contextualized if necessary
1510      */
findDeserializer(DeserializationContext ctxt, JavaType type, BeanProperty property)1511     protected JsonDeserializer<Object> findDeserializer(DeserializationContext ctxt,
1512             JavaType type, BeanProperty property)
1513         throws JsonMappingException
1514     {
1515         return ctxt.findContextualValueDeserializer(type, property);
1516     }
1517 
1518     /**
1519      * Helper method to check whether given text refers to what looks like a clean simple
1520      * integer number, consisting of optional sign followed by a sequence of digits.
1521      *<p>
1522      * Note that definition is quite loose as leading zeroes are allowed, in addition
1523      * to plus sign (not just minus).
1524      */
_isIntNumber(String text)1525     protected final boolean _isIntNumber(String text)
1526     {
1527         final int len = text.length();
1528         if (len > 0) {
1529             char c = text.charAt(0);
1530             // skip leading sign (plus not allowed for strict JSON numbers but...)
1531             int i;
1532 
1533             if (c == '-' || c == '+') {
1534                 if (len == 1) {
1535                     return false;
1536                 }
1537                 i = 1;
1538             } else {
1539                 i = 0;
1540             }
1541             // We will allow leading
1542             for (; i < len; ++i) {
1543                 int ch = text.charAt(i);
1544                 if (ch > '9' || ch < '0') {
1545                     return false;
1546                 }
1547             }
1548             return true;
1549         }
1550         return false;
1551     }
1552 
1553     /*
1554     /**********************************************************
1555     /* Helper methods for: deserializer construction
1556     /**********************************************************
1557      */
1558 
1559     /**
1560      * Helper method that can be used to see if specified property has annotation
1561      * indicating that a converter is to be used for contained values (contents
1562      * of structured types; array/List/Map values)
1563      *
1564      * @param existingDeserializer (optional) configured content
1565      *    serializer if one already exists.
1566      *
1567      * @since 2.2
1568      */
findConvertingContentDeserializer(DeserializationContext ctxt, BeanProperty prop, JsonDeserializer<?> existingDeserializer)1569     protected JsonDeserializer<?> findConvertingContentDeserializer(DeserializationContext ctxt,
1570             BeanProperty prop, JsonDeserializer<?> existingDeserializer)
1571         throws JsonMappingException
1572     {
1573         final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
1574         if (_neitherNull(intr, prop)) {
1575             AnnotatedMember member = prop.getMember();
1576             if (member != null) {
1577                 Object convDef = intr.findDeserializationContentConverter(member);
1578                 if (convDef != null) {
1579                     Converter<Object,Object> conv = ctxt.converterInstance(prop.getMember(), convDef);
1580                     JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
1581                     if (existingDeserializer == null) {
1582                         existingDeserializer = ctxt.findContextualValueDeserializer(delegateType, prop);
1583                     }
1584                     return new StdDelegatingDeserializer<Object>(conv, delegateType, existingDeserializer);
1585                 }
1586             }
1587         }
1588         return existingDeserializer;
1589     }
1590 
1591     /*
1592     /**********************************************************
1593     /* Helper methods for: accessing contextual config settings
1594     /**********************************************************
1595      */
1596 
1597     /**
1598      * Helper method that may be used to find if this deserializer has specific
1599      * {@link JsonFormat} settings, either via property, or through type-specific
1600      * defaulting.
1601      *
1602      * @param typeForDefaults Type (erased) used for finding default format settings, if any
1603      *
1604      * @since 2.7
1605      */
findFormatOverrides(DeserializationContext ctxt, BeanProperty prop, Class<?> typeForDefaults)1606     protected JsonFormat.Value findFormatOverrides(DeserializationContext ctxt,
1607             BeanProperty prop, Class<?> typeForDefaults)
1608     {
1609         if (prop != null) {
1610             return prop.findPropertyFormat(ctxt.getConfig(), typeForDefaults);
1611         }
1612         // even without property or AnnotationIntrospector, may have type-specific defaults
1613         return ctxt.getDefaultPropertyFormat(typeForDefaults);
1614     }
1615 
1616     /**
1617      * Convenience method that uses {@link #findFormatOverrides} to find possible
1618      * defaults and/of overrides, and then calls
1619      * <code>JsonFormat.Value.getFeature(feat)</code>
1620      * to find whether that feature has been specifically marked as enabled or disabled.
1621      *
1622      * @param typeForDefaults Type (erased) used for finding default format settings, if any
1623      *
1624      * @since 2.7
1625      */
findFormatFeature(DeserializationContext ctxt, BeanProperty prop, Class<?> typeForDefaults, JsonFormat.Feature feat)1626     protected Boolean findFormatFeature(DeserializationContext ctxt,
1627             BeanProperty prop, Class<?> typeForDefaults, JsonFormat.Feature feat)
1628     {
1629         JsonFormat.Value format = findFormatOverrides(ctxt, prop, typeForDefaults);
1630         if (format != null) {
1631             return format.getFeature(feat);
1632         }
1633         return null;
1634     }
1635 
1636     /**
1637      * Method called to find {@link NullValueProvider} for a primary property, using
1638      * "value nulls" setting. If no provider found (not defined, or is "skip"),
1639      * will return `null`.
1640      *
1641      * @since 2.9
1642      */
findValueNullProvider(DeserializationContext ctxt, SettableBeanProperty prop, PropertyMetadata propMetadata)1643     protected final NullValueProvider findValueNullProvider(DeserializationContext ctxt,
1644             SettableBeanProperty prop, PropertyMetadata propMetadata)
1645         throws JsonMappingException
1646     {
1647         if (prop != null) {
1648             return _findNullProvider(ctxt, prop, propMetadata.getValueNulls(),
1649                     prop.getValueDeserializer());
1650         }
1651         return null;
1652     }
1653 
1654     /**
1655      * Method called to find {@link NullValueProvider} for a contents of a structured
1656      * primary property (Collection, Map, array), using
1657      * "content nulls" setting. If no provider found (not defined),
1658      * will return given value deserializer (which is a null value provider itself).
1659      *
1660      * @since 2.9
1661      */
findContentNullProvider(DeserializationContext ctxt, BeanProperty prop, JsonDeserializer<?> valueDeser)1662     protected NullValueProvider findContentNullProvider(DeserializationContext ctxt,
1663             BeanProperty prop, JsonDeserializer<?> valueDeser)
1664         throws JsonMappingException
1665     {
1666         final Nulls nulls = findContentNullStyle(ctxt, prop);
1667         if (nulls == Nulls.SKIP) {
1668             return NullsConstantProvider.skipper();
1669         }
1670         // 09-Dec-2019, tatu: [databind#2567] need to ensure correct target type (element,
1671         //    not container), so inlined here before calling _findNullProvider
1672         if (nulls == Nulls.FAIL) {
1673             if (prop == null) {
1674                 JavaType type = ctxt.constructType(valueDeser.handledType());
1675                 // should always be container? But let's double-check just in case:
1676                 if (type.isContainerType()) {
1677                     type = type.getContentType();
1678                 }
1679                 return NullsFailProvider.constructForRootValue(type);
1680             }
1681             return NullsFailProvider.constructForProperty(prop, prop.getType().getContentType());
1682         }
1683 
1684         NullValueProvider prov = _findNullProvider(ctxt, prop, nulls, valueDeser);
1685         if (prov != null) {
1686             return prov;
1687         }
1688         return valueDeser;
1689     }
1690 
findContentNullStyle(DeserializationContext ctxt, BeanProperty prop)1691     protected Nulls findContentNullStyle(DeserializationContext ctxt, BeanProperty prop)
1692         throws JsonMappingException
1693     {
1694         if (prop != null) {
1695             return prop.getMetadata().getContentNulls();
1696         }
1697         return null;
1698     }
1699 
1700     // @since 2.9
_findNullProvider(DeserializationContext ctxt, BeanProperty prop, Nulls nulls, JsonDeserializer<?> valueDeser)1701     protected final NullValueProvider _findNullProvider(DeserializationContext ctxt,
1702             BeanProperty prop, Nulls nulls, JsonDeserializer<?> valueDeser)
1703         throws JsonMappingException
1704     {
1705         if (nulls == Nulls.FAIL) {
1706             if (prop == null) {
1707                 return NullsFailProvider.constructForRootValue(ctxt.constructType(valueDeser.handledType()));
1708             }
1709             return NullsFailProvider.constructForProperty(prop);
1710         }
1711         if (nulls == Nulls.AS_EMPTY) {
1712             // cannot deal with empty values if there is no value deserializer that
1713             // can indicate what "empty value" is:
1714             if (valueDeser == null) {
1715                 return null;
1716             }
1717 
1718             // Let's first do some sanity checking...
1719             // NOTE: although we could use `ValueInstantiator.Gettable` in general,
1720             // let's not since that would prevent being able to use custom impls:
1721             if (valueDeser instanceof BeanDeserializerBase) {
1722                 ValueInstantiator vi = ((BeanDeserializerBase) valueDeser).getValueInstantiator();
1723                 if (!vi.canCreateUsingDefault()) {
1724                     final JavaType type = prop.getType();
1725                     ctxt.reportBadDefinition(type,
1726                             String.format("Cannot create empty instance of %s, no default Creator", type));
1727                 }
1728             }
1729             // Second: can with pre-fetch value?
1730             {
1731                 AccessPattern access = valueDeser.getEmptyAccessPattern();
1732                 if (access == AccessPattern.ALWAYS_NULL) {
1733                     return NullsConstantProvider.nuller();
1734                 }
1735                 if (access == AccessPattern.CONSTANT) {
1736                     return NullsConstantProvider.forValue(valueDeser.getEmptyValue(ctxt));
1737                 }
1738             }
1739             return new NullsAsEmptyProvider(valueDeser);
1740         }
1741         if (nulls == Nulls.SKIP) {
1742             return NullsConstantProvider.skipper();
1743         }
1744         return null;
1745     }
1746 
1747     // @since 2.12
_findCoercionFromEmptyString(DeserializationContext ctxt)1748     protected CoercionAction _findCoercionFromEmptyString(DeserializationContext ctxt) {
1749         return ctxt.findCoercionAction(logicalType(), handledType(),
1750                 CoercionInputShape.EmptyString);
1751     }
1752 
1753     // @since 2.12
_findCoercionFromEmptyArray(DeserializationContext ctxt)1754     protected CoercionAction _findCoercionFromEmptyArray(DeserializationContext ctxt) {
1755         return ctxt.findCoercionAction(logicalType(), handledType(),
1756                 CoercionInputShape.EmptyArray);
1757     }
1758 
1759     // @since 2.12
_findCoercionFromBlankString(DeserializationContext ctxt)1760     protected CoercionAction _findCoercionFromBlankString(DeserializationContext ctxt) {
1761         return ctxt.findCoercionFromBlankString(logicalType(), handledType(),
1762                 CoercionAction.Fail);
1763     }
1764 
1765     /*
1766     /**********************************************************
1767     /* Helper methods for sub-classes, problem reporting
1768     /**********************************************************
1769      */
1770 
1771     /**
1772      * Method called to deal with a property that did not map to a known
1773      * Bean property. Method can deal with the problem as it sees fit (ignore,
1774      * throw exception); but if it does return, it has to skip the matching
1775      * Json content parser has.
1776      *
1777      * @param p Parser that points to value of the unknown property
1778      * @param ctxt Context for deserialization; allows access to the parser,
1779      *    error reporting functionality
1780      * @param instanceOrClass Instance that is being populated by this
1781      *   deserializer, or if not known, Class that would be instantiated.
1782      *   If null, will assume type is what {@link #getValueClass} returns.
1783      * @param propName Name of the property that cannot be mapped
1784      */
handleUnknownProperty(JsonParser p, DeserializationContext ctxt, Object instanceOrClass, String propName)1785     protected void handleUnknownProperty(JsonParser p, DeserializationContext ctxt,
1786             Object instanceOrClass, String propName)
1787         throws IOException
1788     {
1789         if (instanceOrClass == null) {
1790             instanceOrClass = handledType();
1791         }
1792         // Maybe we have configured handler(s) to take care of it?
1793         if (ctxt.handleUnknownProperty(p, this, instanceOrClass, propName)) {
1794             return;
1795         }
1796         /* But if we do get this far, need to skip whatever value we
1797          * are pointing to now (although handler is likely to have done that already)
1798          */
1799         p.skipChildren();
1800     }
1801 
handleMissingEndArrayForSingle(JsonParser p, DeserializationContext ctxt)1802     protected void handleMissingEndArrayForSingle(JsonParser p, DeserializationContext ctxt)
1803         throws IOException
1804     {
1805         ctxt.reportWrongTokenException(this, JsonToken.END_ARRAY,
1806 "Attempted to unwrap '%s' value from an array (with `DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS`) but it contains more than one value",
1807 handledType().getName());
1808         // 05-May-2016, tatu: Should recover somehow (maybe skip until END_ARRAY);
1809         //     but for now just fall through
1810     }
1811 
_verifyEndArrayForSingle(JsonParser p, DeserializationContext ctxt)1812     protected void _verifyEndArrayForSingle(JsonParser p, DeserializationContext ctxt) throws IOException
1813     {
1814         JsonToken t = p.nextToken();
1815         if (t != JsonToken.END_ARRAY) {
1816             handleMissingEndArrayForSingle(p, ctxt);
1817         }
1818     }
1819 
1820     /*
1821     /**********************************************************
1822     /* Helper methods, other
1823     /**********************************************************
1824      */
1825 
1826     /**
1827      * @since 2.9
1828      */
_neitherNull(Object a, Object b)1829     protected final static boolean _neitherNull(Object a, Object b) {
1830         return (a != null) && (b != null);
1831     }
1832 
1833     /**
1834      * @since 2.9
1835      */
_byteOverflow(int value)1836     protected final boolean _byteOverflow(int value) {
1837         // 07-nov-2016, tatu: We support "unsigned byte" as well
1838         //    as Java signed range since that's relatively common usage
1839         return (value < Byte.MIN_VALUE || value > 255);
1840     }
1841 
1842     /**
1843      * @since 2.9
1844      */
_shortOverflow(int value)1845     protected final boolean _shortOverflow(int value) {
1846         return (value < Short.MIN_VALUE || value > Short.MAX_VALUE);
1847     }
1848 
1849     /**
1850      * @since 2.9
1851      */
_intOverflow(long value)1852     protected final boolean _intOverflow(long value) {
1853         return (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE);
1854     }
1855 
1856     /**
1857      * @since 2.9
1858      */
_nonNullNumber(Number n)1859     protected Number _nonNullNumber(Number n) {
1860         if (n == null) {
1861             n = Integer.valueOf(0);
1862         }
1863         return n;
1864     }
1865 }
1866