1 package com.fasterxml.jackson.databind.deser.std;
2
3 import java.io.IOException;
4 import java.math.BigDecimal;
5 import java.math.BigInteger;
6 import java.util.HashSet;
7
8 import com.fasterxml.jackson.core.*;
9 import com.fasterxml.jackson.core.io.NumberInput;
10 import com.fasterxml.jackson.databind.*;
11 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
12 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
13 import com.fasterxml.jackson.databind.util.AccessPattern;
14
15 /**
16  * Container class for deserializers that handle core JDK primitive
17  * (and matching wrapper) types, as well as standard "big" numeric types.
18  * Note that this includes types such as {@link java.lang.Boolean}
19  * and {@link java.lang.Character} which are not strictly numeric,
20  * but are part of primitive/wrapper types.
21  */

22 public class NumberDeserializers
23 {
24     private final static HashSet<String> _classNames = new HashSet<String>();
25     static {
26         // note: can skip primitive types; other ways to check them:
27         Class<?>[] numberTypes = new Class<?>[] {
28             Boolean.class,
29             Byte.class,
30             Short.class,
31             Character.class,
32             Integer.class,
33             Long.class,
34             Float.class,
35             Double.class,
36             // and more generic ones
37             Number.class, BigDecimal.class, BigInteger.class
38         };
39         for (Class<?> cls : numberTypes) {
40             _classNames.add(cls.getName());
41         }
42     }
43
44     public static JsonDeserializer<?> find(Class<?> rawType, String clsName) {
45         if (rawType.isPrimitive()) {
46             if (rawType == Integer.TYPE) {
47                 return IntegerDeserializer.primitiveInstance;
48             }
49             if (rawType == Boolean.TYPE) {
50                 return BooleanDeserializer.primitiveInstance;
51             }
52             if (rawType == Long.TYPE) {
53                 return LongDeserializer.primitiveInstance;
54             }
55             if (rawType == Double.TYPE) {
56                 return DoubleDeserializer.primitiveInstance;
57             }
58             if (rawType == Character.TYPE) {
59                 return CharacterDeserializer.primitiveInstance;
60             }
61             if (rawType == Byte.TYPE) {
62                 return ByteDeserializer.primitiveInstance;
63             }
64             if (rawType == Short.TYPE) {
65                 return ShortDeserializer.primitiveInstance;
66             }
67             if (rawType == Float.TYPE) {
68                 return FloatDeserializer.primitiveInstance;
69             }
70             // [databind#2679]: bit odd place for this (Void.class handled in
71             // `JdkDeserializers`), due to `void` being primitive type
72             if (rawType == Void.TYPE) {
73                 return NullifyingDeserializer.instance;
74             }
75         } else if (_classNames.contains(clsName)) {
76             // Start with most common types; intbooleanlongdouble
77             if (rawType == Integer.class) {
78                 return IntegerDeserializer.wrapperInstance;
79             }
80             if (rawType == Boolean.class) {
81                 return BooleanDeserializer.wrapperInstance;
82             }
83             if (rawType == Long.class) {
84                 return LongDeserializer.wrapperInstance;
85             }
86             if (rawType == Double.class) {
87                 return DoubleDeserializer.wrapperInstance;
88             }
89             if (rawType == Character.class) {
90                 return CharacterDeserializer.wrapperInstance;
91             }
92             if (rawType == Byte.class) {
93                 return ByteDeserializer.wrapperInstance;
94             }
95             if (rawType == Short.class) {
96                 return ShortDeserializer.wrapperInstance;
97             }
98             if (rawType == Float.class) {
99                 return FloatDeserializer.wrapperInstance;
100             }
101             if (rawType == Number.class) {
102                 return NumberDeserializer.instance;
103             }
104             if (rawType == BigDecimal.class) {
105                 return BigDecimalDeserializer.instance;
106             }
107             if (rawType == BigInteger.class) {
108                 return BigIntegerDeserializer.instance;
109             }
110         } else {
111             return null;
112         }
113         // should never occur
114         throw new IllegalArgumentException("Internal error: can't find deserializer for "+rawType.getName());
115     }
116
117     /*
118     /**********************************************************
119     /* Then one intermediate base class for things that have
120     /* both primitive and wrapper types
121     /**********************************************************
122      */

123
124     protected abstract static class PrimitiveOrWrapperDeserializer<T>
125         extends StdScalarDeserializer<T>
126     {
127         private static final long serialVersionUID = 1L;
128
129         protected final T _nullValue;
130
131         // @since 2.9
132         protected final T _emptyValue;
133
134         protected final boolean _primitive;
135
136         protected PrimitiveOrWrapperDeserializer(Class<T> vc, T nvl, T empty) {
137             super(vc);
138             _nullValue = nvl;
139             _emptyValue = empty;
140             _primitive = vc.isPrimitive();
141         }
142
143         @Override
144         public AccessPattern getNullAccessPattern() {
145             // 02-Feb-2017, tatu: For primitives we must dynamically check (and possibly throw
146             //     exception); for wrappers not.
147             if (_primitive) {
148                 return AccessPattern.DYNAMIC;
149             }
150             if (_nullValue == null) {
151                 return AccessPattern.ALWAYS_NULL;
152             }
153             return AccessPattern.CONSTANT;
154         }
155
156         @Override
157         public final T getNullValue(DeserializationContext ctxt) throws JsonMappingException {
158             // 01-Mar-2017, tatu: Alas, not all paths lead to `_coerceNull()`, as `SettableBeanProperty`
159             //    short-circuits `null` handling. Hence need this check as well.
160             if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
161                 ctxt.reportInputMismatch(this,
162                         "Cannot map `null` into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
163                         handledType().toString());
164             }
165             return _nullValue;
166         }
167
168         @Override
169         public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
170             return _emptyValue;
171         }
172     }
173
174     /*
175     /**********************************************************
176     /* Then primitive/wrapper types
177     /**********************************************************
178      */

179
180     @JacksonStdImpl
181     public final static class BooleanDeserializer
182         extends PrimitiveOrWrapperDeserializer<Boolean>
183     {
184         private static final long serialVersionUID = 1L;
185
186         final static BooleanDeserializer primitiveInstance = new BooleanDeserializer(Boolean.TYPE, Boolean.FALSE);
187         final static BooleanDeserializer wrapperInstance = new BooleanDeserializer(Boolean.classnull);
188
189         public BooleanDeserializer(Class<Boolean> cls, Boolean nvl)
190         {
191             super(cls, nvl, Boolean.FALSE);
192         }
193
194         @Override
195         public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
196         {
197             JsonToken t = p.getCurrentToken();
198             if (t == JsonToken.VALUE_TRUE) {
199                 return Boolean.TRUE;
200             }
201             if (t == JsonToken.VALUE_FALSE) {
202                 return Boolean.FALSE;
203             }
204             return _parseBoolean(p, ctxt);
205         }
206
207         // Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
208         // (is it an error to even call this version?)
209         @Override
210         public Boolean deserializeWithType(JsonParser p, DeserializationContext ctxt,
211                 TypeDeserializer typeDeserializer)
212             throws IOException
213         {
214             JsonToken t = p.getCurrentToken();
215             if (t == JsonToken.VALUE_TRUE) {
216                 return Boolean.TRUE;
217             }
218             if (t == JsonToken.VALUE_FALSE) {
219                 return Boolean.FALSE;
220             }
221             return _parseBoolean(p, ctxt);
222         }
223
224         protected final Boolean _parseBoolean(JsonParser p, DeserializationContext ctxt)
225             throws IOException
226         {
227             JsonToken t = p.getCurrentToken();
228             if (t == JsonToken.VALUE_NULL) {
229                 return (Boolean) _coerceNullToken(ctxt, _primitive);
230             }
231             if (t == JsonToken.START_ARRAY) { // unwrapping?
232                 return _deserializeFromArray(p, ctxt);
233             }
234             // should accept ints too, (0 == false, otherwise true)
235             if (t == JsonToken.VALUE_NUMBER_INT) {
236                 return Boolean.valueOf(_parseBooleanFromInt(p, ctxt));
237             }
238             // And finally, let's allow Strings to be converted too
239             if (t == JsonToken.VALUE_STRING) {
240                 String text = p.getText().trim();
241                 // [databind#422]: Allow aliases
242                 if ("true".equals(text) || "True".equals(text)) {
243                     _verifyStringForScalarCoercion(ctxt, text);
244                     return Boolean.TRUE;
245                 }
246                 if ("false".equals(text) || "False".equals(text)) {
247                     _verifyStringForScalarCoercion(ctxt, text);
248                     return Boolean.FALSE;
249                 }
250                 if (text.length() == 0) {
251                     return (Boolean) _coerceEmptyString(ctxt, _primitive);
252                 }
253                 if (_hasTextualNull(text)) {
254                     return (Boolean) _coerceTextualNull(ctxt, _primitive);
255                 }
256                 return (Boolean) ctxt.handleWeirdStringValue(_valueClass, text,
257                         "only \"true\" or \"false\" recognized");
258             }
259             // usually caller should have handled but:
260             if (t == JsonToken.VALUE_TRUE) {
261                 return Boolean.TRUE;
262             }
263             if (t == JsonToken.VALUE_FALSE) {
264                 return Boolean.FALSE;
265             }
266             // Otherwise, no can do:
267             return (Boolean) ctxt.handleUnexpectedToken(_valueClass, p);
268         }
269     }
270
271     @JacksonStdImpl
272     public static class ByteDeserializer
273         extends PrimitiveOrWrapperDeserializer<Byte>
274     {
275         private static final long serialVersionUID = 1L;
276
277         final static ByteDeserializer primitiveInstance = new ByteDeserializer(Byte.TYPE, (byte) 0);
278         final static ByteDeserializer wrapperInstance = new ByteDeserializer(Byte.classnull);
279         
280         public ByteDeserializer(Class<Byte> cls, Byte nvl)
281         {
282             super(cls, nvl, (byte) 0);
283         }
284
285         @Override
286         public Byte deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
287         {
288             if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
289                 return p.getByteValue();
290             }
291             return _parseByte(p, ctxt);
292         }
293
294         protected Byte _parseByte(JsonParser p, DeserializationContext ctxt) throws IOException
295         {
296             JsonToken t = p.getCurrentToken();
297             if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
298                 String text = p.getText().trim();
299                 if (_hasTextualNull(text)) {
300                     return (Byte) _coerceTextualNull(ctxt, _primitive);
301                 }
302                 int len = text.length();
303                 if (len == 0) {
304                     return (Byte) _coerceEmptyString(ctxt, _primitive);
305                 }
306                 _verifyStringForScalarCoercion(ctxt, text);
307                 int value;
308                 try {
309                     value = NumberInput.parseInt(text);
310                 } catch (IllegalArgumentException iae) {
311                     return (Byte) ctxt.handleWeirdStringValue(_valueClass, text,
312                             "not a valid Byte value");
313                 }
314                 // So far so good: but does it fit?
315                 // as per [JACKSON-804], allow range up to 255, inclusive
316                 if (_byteOverflow(value)) {
317                     return (Byte) ctxt.handleWeirdStringValue(_valueClass, text,
318                             "overflow, value cannot be represented as 8-bit value");
319                     // fall-through for deferred fails
320                 }
321                 return Byte.valueOf((byte) value);
322             }
323             if (t == JsonToken.VALUE_NUMBER_FLOAT) {
324                 if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
325                     _failDoubleToIntCoercion(p, ctxt, "Byte");
326                 }
327                 return p.getByteValue();
328             }
329             if (t == JsonToken.VALUE_NULL) {
330                 return (Byte) _coerceNullToken(ctxt, _primitive);
331             }
332             // [databind#381]
333             if (t == JsonToken.START_ARRAY) {
334                 return _deserializeFromArray(p, ctxt);
335             }
336             if (t == JsonToken.VALUE_NUMBER_INT) { // shouldn't usually be called with it but
337                 return p.getByteValue();
338             }
339             return (Byte) ctxt.handleUnexpectedToken(_valueClass, p);
340         }
341     }
342
343     @JacksonStdImpl
344     public static class ShortDeserializer
345         extends PrimitiveOrWrapperDeserializer<Short>
346     {
347         private static final long serialVersionUID = 1L;
348
349         final static ShortDeserializer primitiveInstance = new ShortDeserializer(Short.TYPE, Short.valueOf((short)0));
350         final static ShortDeserializer wrapperInstance = new ShortDeserializer(Short.classnull);
351         
352         public ShortDeserializer(Class<Short> cls, Short nvl)
353         {
354             super(cls, nvl, (short)0);
355         }
356
357         @Override
358         public Short deserialize(JsonParser p, DeserializationContext ctxt)
359             throws IOException
360         {
361             return _parseShort(p, ctxt);
362         }
363
364         protected Short _parseShort(JsonParser p, DeserializationContext ctxt) throws IOException
365         {
366             JsonToken t = p.getCurrentToken();
367             if (t == JsonToken.VALUE_NUMBER_INT) {
368                 return p.getShortValue();
369             }
370             if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
371                 String text = p.getText().trim();
372                 int len = text.length();
373                 if (len == 0) {
374                     return (Short) _coerceEmptyString(ctxt, _primitive);
375                 }
376                 if (_hasTextualNull(text)) {
377                     return (Short) _coerceTextualNull(ctxt, _primitive);
378                 }
379                 _verifyStringForScalarCoercion(ctxt, text);
380                 int value;
381                 try {
382                     value = NumberInput.parseInt(text);
383                 } catch (IllegalArgumentException iae) {
384                     return (Short) ctxt.handleWeirdStringValue(_valueClass, text,
385                             "not a valid Short value");
386                 }
387                 // So far so good: but does it fit?
388                 if (_shortOverflow(value)) {
389                     return (Short) ctxt.handleWeirdStringValue(_valueClass, text,
390                             "overflow, value cannot be represented as 16-bit value");
391                 }
392                 return Short.valueOf((short) value);
393             }
394             if (t == JsonToken.VALUE_NUMBER_FLOAT) {
395                 if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
396                     _failDoubleToIntCoercion(p, ctxt, "Short");
397                 }
398                 return p.getShortValue();
399             }
400             if (t == JsonToken.VALUE_NULL) {
401                 return (Short) _coerceNullToken(ctxt, _primitive);
402             }
403             if (t == JsonToken.START_ARRAY) {
404                 return _deserializeFromArray(p, ctxt);
405             }
406             return (Short) ctxt.handleUnexpectedToken(_valueClass, p);
407         }
408     }
409
410     @JacksonStdImpl
411     public static class CharacterDeserializer
412         extends PrimitiveOrWrapperDeserializer<Character>
413     {
414         private static final long serialVersionUID = 1L;
415
416         final static CharacterDeserializer primitiveInstance = new CharacterDeserializer(Character.TYPE, '\0');
417         final static CharacterDeserializer wrapperInstance = new CharacterDeserializer(Character.classnull);
418         
419         public CharacterDeserializer(Class<Character> cls, Character nvl)
420         {
421             super(cls, nvl, '\0');
422         }
423
424         @Override
425         public Character deserialize(JsonParser p, DeserializationContext ctxt)
426             throws IOException
427         {
428             switch (p.getCurrentTokenId()) {
429             case JsonTokenId.ID_NUMBER_INT: // ok iff ascii value
430                 _verifyNumberForScalarCoercion(ctxt, p);
431                 int value = p.getIntValue();
432                 if (value >= 0 && value <= 0xFFFF) {
433                     return Character.valueOf((char) value);
434                 }
435                 break;
436             case JsonTokenId.ID_STRING: // this is the usual type
437                 // But does it have to be exactly one char?
438                 String text = p.getText();
439                 if (text.length() == 1) {
440                     return Character.valueOf(text.charAt(0));
441                 }
442                 // actually, empty should become null?
443                 if (text.length() == 0) {
444                     return (Character) _coerceEmptyString(ctxt, _primitive);
445                 }
446                 break;
447             case JsonTokenId.ID_NULL:
448                 return (Character) _coerceNullToken(ctxt, _primitive);
449             case JsonTokenId.ID_START_ARRAY:
450                 return _deserializeFromArray(p, ctxt);
451             default:
452             }
453             return (Character) ctxt.handleUnexpectedToken(_valueClass, p);
454         }
455     }
456
457     @JacksonStdImpl
458     public final static class IntegerDeserializer
459         extends PrimitiveOrWrapperDeserializer<Integer>
460     {
461         private static final long serialVersionUID = 1L;
462
463         final static IntegerDeserializer primitiveInstance = new IntegerDeserializer(Integer.TYPE, 0);
464         final static IntegerDeserializer wrapperInstance = new IntegerDeserializer(Integer.classnull);
465         
466         public IntegerDeserializer(Class<Integer> cls, Integer nvl) {
467             super(cls, nvl, 0);
468         }
469
470         // since 2.6, slightly faster lookups for this very common type
471         @Override
472         public boolean isCachable() { return true; }
473
474         @Override
475         public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
476             if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
477                 return p.getIntValue();
478             }
479             return _parseInteger(p, ctxt);
480         }
481
482         // Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
483         // (is it an error to even call this version?)
484         @Override
485         public Integer deserializeWithType(JsonParser p, DeserializationContext ctxt,
486                 TypeDeserializer typeDeserializer) throws IOException
487         {
488             if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
489                 return p.getIntValue();
490             }
491             return _parseInteger(p, ctxt);
492         }
493
494         protected final Integer _parseInteger(JsonParser p, DeserializationContext ctxt) throws IOException
495         {
496             switch (p.getCurrentTokenId()) {
497             // NOTE: caller assumed to usually check VALUE_NUMBER_INT in fast path
498             case JsonTokenId.ID_NUMBER_INT:
499                 return Integer.valueOf(p.getIntValue());
500             case JsonTokenId.ID_NUMBER_FLOAT: // coercing may work too
501                 if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
502                     _failDoubleToIntCoercion(p, ctxt, "Integer");
503                 }
504                 return Integer.valueOf(p.getValueAsInt());
505             case JsonTokenId.ID_STRING: // let's do implicit re-parse
506                 String text = p.getText().trim();
507                 int len = text.length();
508                 if (len == 0) {
509                     return (Integer) _coerceEmptyString(ctxt, _primitive);
510                 }
511                 if (_hasTextualNull(text)) {
512                     return (Integer) _coerceTextualNull(ctxt, _primitive);
513                 }
514                 _verifyStringForScalarCoercion(ctxt, text);
515                 try {
516                     if (len > 9) {
517                         long l = Long.parseLong(text);
518                         if (_intOverflow(l)) {
519                             return (Integer) ctxt.handleWeirdStringValue(_valueClass, text, String.format(
520                                 "Overflow: numeric value (%s) out of range of Integer (%d - %d)",
521                                 text, Integer.MIN_VALUE, Integer.MAX_VALUE));
522                         }
523                         return Integer.valueOf((int) l);
524                     }
525                     return Integer.valueOf(NumberInput.parseInt(text));
526                 } catch (IllegalArgumentException iae) {
527                     return (Integer) ctxt.handleWeirdStringValue(_valueClass, text,
528                             "not a valid Integer value");
529                 }
530             case JsonTokenId.ID_NULL:
531                 return (Integer) _coerceNullToken(ctxt, _primitive);
532             case JsonTokenId.ID_START_ARRAY:
533                 return _deserializeFromArray(p, ctxt);
534             }
535             // Otherwise, no can do:
536             return (Integer) ctxt.handleUnexpectedToken(_valueClass, p);
537         }
538     }
539
540     @JacksonStdImpl
541     public final static class LongDeserializer
542         extends PrimitiveOrWrapperDeserializer<Long>
543     {
544         private static final long serialVersionUID = 1L;
545
546         final static LongDeserializer primitiveInstance = new LongDeserializer(Long.TYPE, 0L);
547         final static LongDeserializer wrapperInstance = new LongDeserializer(Long.classnull);
548         
549         public LongDeserializer(Class<Long> cls, Long nvl) {
550             super(cls, nvl, 0L);
551         }
552
553         // since 2.6, slightly faster lookups for this very common type
554         @Override
555         public boolean isCachable() { return true; }
556         
557         @Override
558         public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
559             if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
560                 return p.getLongValue();
561             }
562             return _parseLong(p, ctxt);
563         }
564
565         protected final Long _parseLong(JsonParser p, DeserializationContext ctxt) throws IOException
566         {
567             switch (p.getCurrentTokenId()) {
568             // NOTE: caller assumed to usually check VALUE_NUMBER_INT in fast path
569             case JsonTokenId.ID_NUMBER_INT:
570                 return p.getLongValue();
571             case JsonTokenId.ID_NUMBER_FLOAT:
572                 if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
573                     _failDoubleToIntCoercion(p, ctxt, "Long");
574                 }
575                 return p.getValueAsLong();
576             case JsonTokenId.ID_STRING:
577                 String text = p.getText().trim();
578                 if (text.length() == 0) {
579                     return (Long) _coerceEmptyString(ctxt, _primitive);
580                 }
581                 if (_hasTextualNull(text)) {
582                     return (Long) _coerceTextualNull(ctxt, _primitive);
583                 }
584                 _verifyStringForScalarCoercion(ctxt, text);
585                 // let's allow Strings to be converted too
586                 try {
587                     return Long.valueOf(NumberInput.parseLong(text));
588                 } catch (IllegalArgumentException iae) { }
589                 return (Long) ctxt.handleWeirdStringValue(_valueClass, text,
590                         "not a valid Long value");
591                 // fall-through
592             case JsonTokenId.ID_NULL:
593                 return (Long) _coerceNullToken(ctxt, _primitive);
594             case JsonTokenId.ID_START_ARRAY:
595                 return _deserializeFromArray(p, ctxt);
596             }
597             // Otherwise, no can do:
598             return (Long) ctxt.handleUnexpectedToken(_valueClass, p);
599         }
600     }
601
602     @JacksonStdImpl
603     public static class FloatDeserializer
604         extends PrimitiveOrWrapperDeserializer<Float>
605     {
606         private static final long serialVersionUID = 1L;
607
608         final static FloatDeserializer primitiveInstance = new FloatDeserializer(Float.TYPE, 0.f);
609         final static FloatDeserializer wrapperInstance = new FloatDeserializer(Float.classnull);
610         
611         public FloatDeserializer(Class<Float> cls, Float nvl) {
612             super(cls, nvl, 0.f);
613         }
614
615         @Override
616         public Float deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
617         {
618             return _parseFloat(p, ctxt);
619         }
620
621         protected final Float _parseFloat(JsonParser p, DeserializationContext ctxt)
622             throws IOException
623         {
624             // We accept couple of different types; obvious ones first:
625             JsonToken t = p.getCurrentToken();
626             
627             if (t == JsonToken.VALUE_NUMBER_FLOAT || t == JsonToken.VALUE_NUMBER_INT) { // coercing should work too
628                 return p.getFloatValue();
629             }
630             // And finally, let's allow Strings to be converted too
631             if (t == JsonToken.VALUE_STRING) {
632                 String text = p.getText().trim();
633                 if ((text.length() == 0)) {
634                     return (Float) _coerceEmptyString(ctxt, _primitive);
635                 }
636                 if (_hasTextualNull(text)) {
637                     return (Float) _coerceTextualNull(ctxt, _primitive);
638                 }
639                 switch (text.charAt(0)) {
640                 case 'I':
641                     if (_isPosInf(text)) {
642                         return Float.POSITIVE_INFINITY;
643                     }
644                     break;
645                 case 'N':
646                     if (_isNaN(text)) {
647                         return Float.NaN;
648                     }
649                     break;
650                 case '-':
651                     if (_isNegInf(text)) {
652                         return Float.NEGATIVE_INFINITY;
653                     }
654                     break;
655                 }
656                 _verifyStringForScalarCoercion(ctxt, text);
657                 try {
658                     return Float.parseFloat(text);
659                 } catch (IllegalArgumentException iae) { }
660                 return (Float) ctxt.handleWeirdStringValue(_valueClass, text,
661                         "not a valid Float value");
662             }
663             if (t == JsonToken.VALUE_NULL) {
664                 return (Float) _coerceNullToken(ctxt, _primitive);
665             }
666             if (t == JsonToken.START_ARRAY) {
667                 return _deserializeFromArray(p, ctxt);
668             }
669             // Otherwise, no can do:
670             return (Float) ctxt.handleUnexpectedToken(_valueClass, p);
671         }
672     }
673
674     @JacksonStdImpl
675     public static class DoubleDeserializer
676         extends PrimitiveOrWrapperDeserializer<Double>
677     {
678         private static final long serialVersionUID = 1L;
679
680         final static DoubleDeserializer primitiveInstance = new DoubleDeserializer(Double.TYPE, 0.d);
681         final static DoubleDeserializer wrapperInstance = new DoubleDeserializer(Double.classnull);
682         
683         public DoubleDeserializer(Class<Double> cls, Double nvl) {
684             super(cls, nvl, 0.d);
685         }
686
687         @Override
688         public Double deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
689             return _parseDouble(p, ctxt);
690         }
691
692         // Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
693         // (is it an error to even call this version?)
694         @Override
695         public Double deserializeWithType(JsonParser p, DeserializationContext ctxt,
696                 TypeDeserializer typeDeserializer) throws IOException
697         {
698             return _parseDouble(p, ctxt);
699         }
700
701         protected final Double _parseDouble(JsonParser p, DeserializationContext ctxt) throws IOException
702         {
703             JsonToken t = p.getCurrentToken();
704             if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) { // coercing should work too
705                 return p.getDoubleValue();
706             }
707             if (t == JsonToken.VALUE_STRING) {
708                 String text = p.getText().trim();
709                 if ((text.length() == 0)) {
710                     return (Double) _coerceEmptyString(ctxt, _primitive);
711                 }
712                 if (_hasTextualNull(text)) {
713                     return (Double) _coerceTextualNull(ctxt, _primitive);
714                 }
715                 switch (text.charAt(0)) {
716                 case 'I':
717                     if (_isPosInf(text)) {
718                         return Double.POSITIVE_INFINITY;
719                     }
720                     break;
721                 case 'N':
722                     if (_isNaN(text)) {
723                         return Double.NaN;
724                     }
725                     break;
726                 case '-':
727                     if (_isNegInf(text)) {
728                         return Double.NEGATIVE_INFINITY;
729                     }
730                     break;
731                 }
732                 _verifyStringForScalarCoercion(ctxt, text);
733                 try {
734                     return parseDouble(text);
735                 } catch (IllegalArgumentException iae) { }
736                 return (Double) ctxt.handleWeirdStringValue(_valueClass, text,
737                         "not a valid Double value");
738             }
739             if (t == JsonToken.VALUE_NULL) {
740                 return (Double) _coerceNullToken(ctxt, _primitive);
741             }
742             if (t == JsonToken.START_ARRAY) {
743                 return _deserializeFromArray(p, ctxt);
744             }
745             // Otherwise, no can do:
746             return (Double) ctxt.handleUnexpectedToken(_valueClass, p);
747         }
748     }
749
750     /**
751      * For type <code>Number.class</code>, we can just rely on type
752      * mappings that plain {@link JsonParser#getNumberValue} returns.
753      *<p>
754      * There is one additional complication: some numeric
755      * types (specifically, int/Integer and double/Double) are "non-typed";
756      * meaning that they will NEVER be output with type information.
757      * But other numeric types may need such type information.
758      * This is why {@link #deserializeWithType} must be overridden.
759      */

760     @SuppressWarnings("serial")
761     @JacksonStdImpl
762     public static class NumberDeserializer
763         extends StdScalarDeserializer<Object>
764     {
765         public final static NumberDeserializer instance = new NumberDeserializer();
766         
767         public NumberDeserializer() {
768             super(Number.class);
769         }
770
771         @Override
772         public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
773         {
774             switch (p.getCurrentTokenId()) {
775             case JsonTokenId.ID_NUMBER_INT:
776                 if (ctxt.hasSomeOfFeatures(F_MASK_INT_COERCIONS)) {
777                     return _coerceIntegral(p, ctxt);
778                 }
779                 return p.getNumberValue();
780
781             case JsonTokenId.ID_NUMBER_FLOAT:
782                 if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
783                     // 10-Mar-2017, tatu: NaN and BigDecimal won't mix...
784                     if (!p.isNaN()) {
785                         return p.getDecimalValue();
786                     }
787                 }
788                 return p.getNumberValue();
789
790             case JsonTokenId.ID_STRING:
791                 /* Textual values are more difficult... not parsing itself, but figuring
792                  * out 'minimal' type to use 
793                  */

794                 String text = p.getText().trim();
795                 if ((text.length() == 0)) {
796                     // note: no need to call `coerce` as this is never primitive
797                     return getNullValue(ctxt);
798                 }
799                 if (_hasTextualNull(text)) {
800                     // note: no need to call `coerce` as this is never primitive
801                     return getNullValue(ctxt);
802                 }
803                 if (_isPosInf(text)) {
804                     return Double.POSITIVE_INFINITY;
805                 }
806                 if (_isNegInf(text)) {
807                     return Double.NEGATIVE_INFINITY;
808                 }
809                 if (_isNaN(text)) {
810                     return Double.NaN;
811                 }
812                 _verifyStringForScalarCoercion(ctxt, text);
813                 try {
814                     if (!_isIntNumber(text)) {
815                         if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
816                             return new BigDecimal(text);
817                         }
818                         return Double.valueOf(text);
819                     }
820                     if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) {
821                         return new BigInteger(text);
822                     }
823                     long value = Long.parseLong(text);
824                     if (!ctxt.isEnabled(DeserializationFeature.USE_LONG_FOR_INTS)) {
825                         if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
826                             return Integer.valueOf((int) value);
827                         }
828                     }
829                     return Long.valueOf(value);
830                 } catch (IllegalArgumentException iae) {
831                     return ctxt.handleWeirdStringValue(_valueClass, text,
832                             "not a valid number");
833                 }
834             case JsonTokenId.ID_START_ARRAY:
835                 return _deserializeFromArray(p, ctxt);
836             }
837             // Otherwise, no can do:
838             return ctxt.handleUnexpectedToken(_valueClass, p);
839         }
840
841         /**
842          * As mentioned in class Javadoc, there is additional complexity in
843          * handling potentially mixed type information here. Because of this,
844          * we must actually check for "raw" integers and doubles first, before
845          * calling type deserializer.
846          */

847         @Override
848         public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
849                 TypeDeserializer typeDeserializer)
850             throws IOException
851         {
852             switch (p.getCurrentTokenId()) {
853             case JsonTokenId.ID_NUMBER_INT:
854             case JsonTokenId.ID_NUMBER_FLOAT:
855             case JsonTokenId.ID_STRING:
856                 // cannot point to type information: hence must be non-typed (int/double)
857                 return deserialize(p, ctxt);
858             }
859             return typeDeserializer.deserializeTypedFromScalar(p, ctxt);
860         }
861     }
862
863     /*
864     /**********************************************************
865     /* And then bit more complicated (but non-structured) number
866     /* types
867     /**********************************************************
868      */

869
870     /**
871      * This is bit trickier to implement efficiently, while avoiding
872      * overflow problems.
873      */

874     @SuppressWarnings("serial")
875     @JacksonStdImpl
876     public static class BigIntegerDeserializer
877         extends StdScalarDeserializer<BigInteger>
878     {
879         public final static BigIntegerDeserializer instance = new BigIntegerDeserializer();
880
881         public BigIntegerDeserializer() { super(BigInteger.class); }
882
883         @Override
884         public Object getEmptyValue(DeserializationContext ctxt) {
885             return BigInteger.ZERO;
886         }
887
888         @SuppressWarnings("incomplete-switch")
889         @Override
890         public BigInteger deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
891         {
892             switch (p.getCurrentTokenId()) {
893             case JsonTokenId.ID_NUMBER_INT:
894                 switch (p.getNumberType()) {
895                 case INT:
896                 case LONG:
897                 case BIG_INTEGER:
898                     return p.getBigIntegerValue();
899                 }
900                 break;
901             case JsonTokenId.ID_NUMBER_FLOAT:
902                 if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
903                     _failDoubleToIntCoercion(p, ctxt, "java.math.BigInteger");
904                 }
905                 return p.getDecimalValue().toBigInteger();
906             case JsonTokenId.ID_START_ARRAY:
907                 return _deserializeFromArray(p, ctxt);
908             case JsonTokenId.ID_STRING: // let's do implicit re-parse
909                 String text = p.getText().trim();
910                 // note: no need to call `coerce` as this is never primitive
911                 if (_isEmptyOrTextualNull(text)) {
912                     _verifyNullForScalarCoercion(ctxt, text);
913                     return getNullValue(ctxt);
914                 }
915                 _verifyStringForScalarCoercion(ctxt, text);
916                 try {
917                     return new BigInteger(text);
918                 } catch (IllegalArgumentException iae) { }
919                 return (BigInteger) ctxt.handleWeirdStringValue(_valueClass, text,
920                         "not a valid representation");
921             }
922             // String is ok too, can easily convert; otherwise, no can do:
923             return (BigInteger) ctxt.handleUnexpectedToken(_valueClass, p);
924         }
925     }
926     
927     @SuppressWarnings("serial")
928     @JacksonStdImpl
929     public static class BigDecimalDeserializer
930         extends StdScalarDeserializer<BigDecimal>
931     {
932         public final static BigDecimalDeserializer instance = new BigDecimalDeserializer();
933  
934         public BigDecimalDeserializer() { super(BigDecimal.class); }
935
936         @Override
937         public Object getEmptyValue(DeserializationContext ctxt) {
938             return BigDecimal.ZERO;
939         }
940         
941         @Override
942         public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt)
943             throws IOException
944         {
945             switch (p.getCurrentTokenId()) {
946             case JsonTokenId.ID_NUMBER_INT:
947             case JsonTokenId.ID_NUMBER_FLOAT:
948                 return p.getDecimalValue();
949             case JsonTokenId.ID_STRING:
950                 String text = p.getText().trim();
951                 // note: no need to call `coerce` as this is never primitive
952                 if (_isEmptyOrTextualNull(text)) {
953                     _verifyNullForScalarCoercion(ctxt, text);
954                     return getNullValue(ctxt);
955                 }
956                 _verifyStringForScalarCoercion(ctxt, text);
957                 try {
958                     return new BigDecimal(text);
959                 } catch (IllegalArgumentException iae) { }
960                 return (BigDecimal) ctxt.handleWeirdStringValue(_valueClass, text,
961                         "not a valid representation");
962             case JsonTokenId.ID_START_ARRAY:
963                 return _deserializeFromArray(p, ctxt);
964             }
965             // Otherwise, no can do:
966             return (BigDecimal) ctxt.handleUnexpectedToken(_valueClass, p);
967         }
968     }
969 }
970