com.fasterxml.jackson.databind.deser.std.NumberDeserializers Maven / Gradle / Ivy
The newest version!
package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashSet;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.cfg.CoercionAction;
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.type.LogicalType;
import com.fasterxml.jackson.databind.util.AccessPattern;
import com.fasterxml.jackson.databind.util.ClassUtil;
/**
* Container class for deserializers that handle core JDK primitive
* (and matching wrapper) types, as well as standard "big" numeric types.
* Note that this includes types such as {@link java.lang.Boolean}
* and {@link java.lang.Character} which are not strictly numeric,
* but are part of primitive/wrapper types.
*/
public class NumberDeserializers
{
private final static HashSet _classNames = new HashSet();
static {
// note: can skip primitive types; other ways to check them:
Class>[] numberTypes = new Class>[] {
Boolean.class,
Byte.class,
Short.class,
Character.class,
Integer.class,
Long.class,
Float.class,
Double.class,
// and more generic ones
Number.class, BigDecimal.class, BigInteger.class
};
for (Class> cls : numberTypes) {
_classNames.add(cls.getName());
}
}
public static JsonDeserializer> find(Class> rawType, String clsName) {
if (rawType.isPrimitive()) {
if (rawType == Integer.TYPE) {
return IntegerDeserializer.primitiveInstance;
}
if (rawType == Boolean.TYPE) {
return BooleanDeserializer.primitiveInstance;
}
if (rawType == Long.TYPE) {
return LongDeserializer.primitiveInstance;
}
if (rawType == Double.TYPE) {
return DoubleDeserializer.primitiveInstance;
}
if (rawType == Character.TYPE) {
return CharacterDeserializer.primitiveInstance;
}
if (rawType == Byte.TYPE) {
return ByteDeserializer.primitiveInstance;
}
if (rawType == Short.TYPE) {
return ShortDeserializer.primitiveInstance;
}
if (rawType == Float.TYPE) {
return FloatDeserializer.primitiveInstance;
}
// [databind#2679]: bit odd place for this (Void.class handled in
// `JdkDeserializers`), due to `void` being primitive type
if (rawType == Void.TYPE) {
return NullifyingDeserializer.instance;
}
} else if (_classNames.contains(clsName)) {
// Start with most common types; int, boolean, long, double
if (rawType == Integer.class) {
return IntegerDeserializer.wrapperInstance;
}
if (rawType == Boolean.class) {
return BooleanDeserializer.wrapperInstance;
}
if (rawType == Long.class) {
return LongDeserializer.wrapperInstance;
}
if (rawType == Double.class) {
return DoubleDeserializer.wrapperInstance;
}
if (rawType == Character.class) {
return CharacterDeserializer.wrapperInstance;
}
if (rawType == Byte.class) {
return ByteDeserializer.wrapperInstance;
}
if (rawType == Short.class) {
return ShortDeserializer.wrapperInstance;
}
if (rawType == Float.class) {
return FloatDeserializer.wrapperInstance;
}
if (rawType == Number.class) {
return NumberDeserializer.instance;
}
if (rawType == BigDecimal.class) {
return BigDecimalDeserializer.instance;
}
if (rawType == BigInteger.class) {
return BigIntegerDeserializer.instance;
}
} else {
return null;
}
// should never occur
throw new IllegalArgumentException("Internal error: can't find deserializer for "+rawType.getName());
}
/*
/**********************************************************
/* Then one intermediate base class for things that have
/* both primitive and wrapper types
/**********************************************************
*/
protected abstract static class PrimitiveOrWrapperDeserializer
extends StdScalarDeserializer
{
private static final long serialVersionUID = 1L;
// @since 2.12
protected final LogicalType _logicalType;
protected final T _nullValue;
// @since 2.9
protected final T _emptyValue;
protected final boolean _primitive;
// @since 2.12
protected PrimitiveOrWrapperDeserializer(Class vc, LogicalType logicalType,
T nvl, T empty) {
super(vc);
_logicalType = logicalType;
_nullValue = nvl;
_emptyValue = empty;
_primitive = vc.isPrimitive();
}
@Deprecated // since 2.12
protected PrimitiveOrWrapperDeserializer(Class vc, T nvl, T empty) {
this(vc, LogicalType.OtherScalar, nvl, empty);
}
@Override
public AccessPattern getNullAccessPattern() {
// 02-Feb-2017, tatu: For primitives we must dynamically check (and possibly throw
// exception); for wrappers not.
if (_primitive) {
return AccessPattern.DYNAMIC;
}
if (_nullValue == null) {
return AccessPattern.ALWAYS_NULL;
}
return AccessPattern.CONSTANT;
}
@Override
public final T getNullValue(DeserializationContext ctxt) throws JsonMappingException {
// 01-Mar-2017, tatu: Alas, not all paths lead to `_coerceNull()`, as `SettableBeanProperty`
// short-circuits `null` handling. Hence need this check as well.
if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Cannot map `null` into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
ClassUtil.classNameOf(handledType()));
}
return _nullValue;
}
@Override
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
return _emptyValue;
}
@Override // since 2.12
public final LogicalType logicalType() {
return _logicalType;
}
}
/*
/**********************************************************
/* Then primitive/wrapper types
/**********************************************************
*/
@JacksonStdImpl
public final static class BooleanDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static BooleanDeserializer primitiveInstance = new BooleanDeserializer(Boolean.TYPE, Boolean.FALSE);
final static BooleanDeserializer wrapperInstance = new BooleanDeserializer(Boolean.class, null);
public BooleanDeserializer(Class cls, Boolean nvl)
{
super(cls, LogicalType.Boolean, nvl, Boolean.FALSE);
}
@Override
public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
JsonToken t = p.currentToken();
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
if (_primitive) {
return _parseBooleanPrimitive(p, ctxt);
}
return _parseBoolean(p, ctxt, _valueClass);
}
// Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
// (is it an error to even call this version?)
@Override
public Boolean deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws IOException
{
JsonToken t = p.currentToken();
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
if (_primitive) {
return _parseBooleanPrimitive(p, ctxt);
}
return _parseBoolean(p, ctxt, _valueClass);
}
}
@JacksonStdImpl
public static class ByteDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static ByteDeserializer primitiveInstance = new ByteDeserializer(Byte.TYPE, (byte) 0);
final static ByteDeserializer wrapperInstance = new ByteDeserializer(Byte.class, null);
public ByteDeserializer(Class cls, Byte nvl)
{
super(cls, LogicalType.Integer, nvl, (byte) 0);
}
@Override
public Byte deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
if (p.isExpectedNumberIntToken()) {
return p.getByteValue();
}
if (_primitive) {
return _parseBytePrimitive(p, ctxt);
}
return _parseByte(p, ctxt);
}
protected Byte _parseByte(JsonParser p, DeserializationContext ctxt)
throws IOException
{
String text;
switch (p.currentTokenId()) {
case JsonTokenId.ID_STRING: // let's do implicit re-parse
text = p.getText();
break;
case JsonTokenId.ID_NUMBER_FLOAT:
final CoercionAction act = _checkFloatToIntCoercion(p, ctxt, _valueClass);
if (act == CoercionAction.AsNull) {
return (Byte) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Byte) getEmptyValue(ctxt);
}
return p.getByteValue();
case JsonTokenId.ID_NULL: // null fine for non-primitive
return (Byte) getNullValue(ctxt);
case JsonTokenId.ID_NUMBER_INT:
return p.getByteValue();
case JsonTokenId.ID_START_ARRAY:
return (Byte) _deserializeFromArray(p, ctxt);
// 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
case JsonTokenId.ID_START_OBJECT:
text = ctxt.extractScalarFromObject(p, this, _valueClass);
break;
default:
return (Byte) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
// Rest of the processing is for coercion from String
final CoercionAction act = _checkFromStringCoercion(ctxt, text);
if (act == CoercionAction.AsNull) {
return (Byte) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Byte) getEmptyValue(ctxt);
}
text = text.trim();
if (_checkTextualNull(ctxt, text)) {
return (Byte) getNullValue(ctxt);
}
int value;
try {
value = NumberInput.parseInt(text);
} catch (IllegalArgumentException iae) {
return (Byte) ctxt.handleWeirdStringValue(_valueClass, text,
"not a valid Byte value");
}
// So far so good: but does it fit?
// as per [JACKSON-804], allow range up to 255, inclusive
if (_byteOverflow(value)) {
return (Byte) ctxt.handleWeirdStringValue(_valueClass, text,
"overflow, value cannot be represented as 8-bit value");
// fall-through for deferred fails
}
return Byte.valueOf((byte) value);
}
}
@JacksonStdImpl
public static class ShortDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static ShortDeserializer primitiveInstance = new ShortDeserializer(Short.TYPE, Short.valueOf((short)0));
final static ShortDeserializer wrapperInstance = new ShortDeserializer(Short.class, null);
public ShortDeserializer(Class cls, Short nvl)
{
super(cls, LogicalType.Integer, nvl, (short)0);
}
@Override
public Short deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException
{
if (p.isExpectedNumberIntToken()) {
return p.getShortValue();
}
if (_primitive) {
return _parseShortPrimitive(p, ctxt);
}
return _parseShort(p, ctxt);
}
protected Short _parseShort(JsonParser p, DeserializationContext ctxt)
throws IOException
{
String text;
switch (p.currentTokenId()) {
case JsonTokenId.ID_STRING: // let's do implicit re-parse
text = p.getText();
break;
case JsonTokenId.ID_NUMBER_FLOAT:
final CoercionAction act = _checkFloatToIntCoercion(p, ctxt, _valueClass);
if (act == CoercionAction.AsNull) {
return (Short) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Short) getEmptyValue(ctxt);
}
return p.getShortValue();
case JsonTokenId.ID_NULL: // null fine for non-primitive
return (Short) getNullValue(ctxt);
case JsonTokenId.ID_NUMBER_INT:
return p.getShortValue();
// 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
case JsonTokenId.ID_START_OBJECT:
text = ctxt.extractScalarFromObject(p, this, _valueClass);
break;
case JsonTokenId.ID_START_ARRAY:
return (Short)_deserializeFromArray(p, ctxt);
default:
return (Short) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
// Rest of the processing is for coercion from String
final CoercionAction act = _checkFromStringCoercion(ctxt, text);
if (act == CoercionAction.AsNull) {
return (Short) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Short) getEmptyValue(ctxt);
}
text = text.trim();
if (_checkTextualNull(ctxt, text)) {
return (Short) getNullValue(ctxt);
}
int value;
try {
value = NumberInput.parseInt(text);
} catch (IllegalArgumentException iae) {
return (Short) ctxt.handleWeirdStringValue(_valueClass, text,
"not a valid Short value");
}
// So far so good: but does it fit?
if (_shortOverflow(value)) {
return (Short) ctxt.handleWeirdStringValue(_valueClass, text,
"overflow, value cannot be represented as 16-bit value");
}
return (short) value;
}
}
@JacksonStdImpl
public static class CharacterDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static CharacterDeserializer primitiveInstance = new CharacterDeserializer(Character.TYPE, '\0');
final static CharacterDeserializer wrapperInstance = new CharacterDeserializer(Character.class, null);
public CharacterDeserializer(Class cls, Character nvl)
{
super(cls,
// 07-Jun-2020, tatu: Debatable if it should be "OtherScalar" or Integer but...
LogicalType.Integer, nvl, '\0');
}
@Override
public Character deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException
{
String text;
switch (p.currentTokenId()) {
case JsonTokenId.ID_STRING:
// 23-Jun-2020, tatu: Unlike real numeric types, Character/char does not
// have canonical shape in JSON, and String in particular does not need
// coercion -- as long as it has length of 1.
text = p.getText();
break;
case JsonTokenId.ID_NUMBER_INT: // ok iff Unicode value
CoercionAction act = ctxt.findCoercionAction(logicalType(), _valueClass, CoercionInputShape.Integer);
switch (act) {
case Fail:
_checkCoercionFail(ctxt, act, _valueClass, p.getNumberValue(),
"Integer value ("+p.getText()+")");
// fall-through in unlikely case of returning
case AsNull:
return getNullValue(ctxt);
case AsEmpty:
return (Character) getEmptyValue(ctxt);
default:
}
int value = p.getIntValue();
if (value >= 0 && value <= 0xFFFF) {
return Character.valueOf((char) value);
}
return (Character) ctxt.handleWeirdNumberValue(handledType(), value,
"value outside valid Character range (0x0000 - 0xFFFF)");
case JsonTokenId.ID_NULL:
if (_primitive) {
_verifyNullForPrimitive(ctxt);
}
return (Character) getNullValue(ctxt);
// 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
case JsonTokenId.ID_START_OBJECT:
text = ctxt.extractScalarFromObject(p, this, _valueClass);
break;
case JsonTokenId.ID_START_ARRAY:
return _deserializeFromArray(p, ctxt);
default:
return (Character) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
if (text.length() == 1) {
return Character.valueOf(text.charAt(0));
}
CoercionAction act = _checkFromStringCoercion(ctxt, text);
if (act == CoercionAction.AsNull) {
return getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Character) getEmptyValue(ctxt);
}
text = text.trim();
if (_checkTextualNull(ctxt, text)) {
return (Character) getNullValue(ctxt);
}
return (Character) ctxt.handleWeirdStringValue(handledType(), text,
"Expected either Integer value code or 1-character String");
}
}
@JacksonStdImpl
public final static class IntegerDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static IntegerDeserializer primitiveInstance = new IntegerDeserializer(Integer.TYPE, 0);
final static IntegerDeserializer wrapperInstance = new IntegerDeserializer(Integer.class, null);
public IntegerDeserializer(Class cls, Integer nvl) {
super(cls, LogicalType.Integer, nvl, 0);
}
// since 2.6, slightly faster lookups for this very common type
@Override
public boolean isCachable() { return true; }
@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.isExpectedNumberIntToken()) {
return p.getIntValue();
}
if (_primitive) {
return _parseIntPrimitive(p, ctxt);
}
return _parseInteger(p, ctxt, Integer.class);
}
// Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
// (is it an error to even call this version?)
@Override
public Integer deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer) throws IOException
{
if (p.isExpectedNumberIntToken()) {
return p.getIntValue();
}
if (_primitive) {
return _parseIntPrimitive(p, ctxt);
}
return _parseInteger(p, ctxt, Integer.class);
}
}
@JacksonStdImpl
public final static class LongDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static LongDeserializer primitiveInstance = new LongDeserializer(Long.TYPE, 0L);
final static LongDeserializer wrapperInstance = new LongDeserializer(Long.class, null);
public LongDeserializer(Class cls, Long nvl) {
super(cls, LogicalType.Integer, nvl, 0L);
}
// since 2.6, slightly faster lookups for this very common type
@Override
public boolean isCachable() { return true; }
@Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.isExpectedNumberIntToken()) {
return p.getLongValue();
}
if (_primitive) {
return _parseLongPrimitive(p, ctxt);
}
return _parseLong(p, ctxt, Long.class);
}
}
@JacksonStdImpl
public static class FloatDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static FloatDeserializer primitiveInstance = new FloatDeserializer(Float.TYPE, 0.f);
final static FloatDeserializer wrapperInstance = new FloatDeserializer(Float.class, null);
public FloatDeserializer(Class cls, Float nvl) {
super(cls, LogicalType.Float, nvl, 0.f);
}
@Override
public Float deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
return p.getFloatValue();
}
if (_primitive) {
return _parseFloatPrimitive(p, ctxt);
}
return _parseFloat(p, ctxt);
}
protected final Float _parseFloat(JsonParser p, DeserializationContext ctxt)
throws IOException
{
String text;
switch (p.currentTokenId()) {
case JsonTokenId.ID_STRING:
text = p.getText();
break;
case JsonTokenId.ID_NULL: // null fine for non-primitive
return (Float) getNullValue(ctxt);
case JsonTokenId.ID_NUMBER_INT:
final CoercionAction act = _checkIntToFloatCoercion(p, ctxt, _valueClass);
if (act == CoercionAction.AsNull) {
return (Float) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Float) getEmptyValue(ctxt);
}
// fall through to coerce
case JsonTokenId.ID_NUMBER_FLOAT:
return p.getFloatValue();
// 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
case JsonTokenId.ID_START_OBJECT:
text = ctxt.extractScalarFromObject(p, this, _valueClass);
break;
case JsonTokenId.ID_START_ARRAY:
return _deserializeFromArray(p, ctxt);
default:
return (Float) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
// 18-Nov-2020, tatu: Special case, Not-a-Numbers as String need to be
// considered "native" representation as JSON does not allow as numbers,
// and hence not bound by coercion rules
{
Float nan = _checkFloatSpecialValue(text);
if (nan != null) {
return nan;
}
}
final CoercionAction act = _checkFromStringCoercion(ctxt, text);
if (act == CoercionAction.AsNull) {
return (Float) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Float) getEmptyValue(ctxt);
}
text = text.trim();
if (_checkTextualNull(ctxt, text)) {
return (Float) getNullValue(ctxt);
}
// 09-Dec-2023, tatu: To avoid parser having to validate input, pre-validate:
if (NumberInput.looksLikeValidNumber(text)) {
p.streamReadConstraints().validateFPLength(text.length());
try {
return NumberInput.parseFloat(text, p.isEnabled(StreamReadFeature.USE_FAST_DOUBLE_PARSER));
} catch (IllegalArgumentException iae) {
if (true) throw new Error();
}
}
return (Float) ctxt.handleWeirdStringValue(_valueClass, text,
"not a valid `Float` value");
}
}
@JacksonStdImpl
public static class DoubleDeserializer
extends PrimitiveOrWrapperDeserializer
{
private static final long serialVersionUID = 1L;
final static DoubleDeserializer primitiveInstance = new DoubleDeserializer(Double.TYPE, 0.d);
final static DoubleDeserializer wrapperInstance = new DoubleDeserializer(Double.class, null);
public DoubleDeserializer(Class cls, Double nvl) {
super(cls, LogicalType.Float, nvl, 0.d);
}
@Override
public Double deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
return p.getDoubleValue();
}
if (_primitive) {
return _parseDoublePrimitive(p, ctxt);
}
return _parseDouble(p, ctxt);
}
// Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
// (is it an error to even call this version?)
@Override
public Double deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer) throws IOException
{
if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
return p.getDoubleValue();
}
if (_primitive) {
return _parseDoublePrimitive(p, ctxt);
}
return _parseDouble(p, ctxt);
}
protected final Double _parseDouble(JsonParser p, DeserializationContext ctxt) throws IOException
{
String text;
switch (p.currentTokenId()) {
case JsonTokenId.ID_STRING:
text = p.getText();
break;
case JsonTokenId.ID_NULL: // null fine for non-primitive
return (Double) getNullValue(ctxt);
case JsonTokenId.ID_NUMBER_INT:
final CoercionAction act = _checkIntToFloatCoercion(p, ctxt, _valueClass);
if (act == CoercionAction.AsNull) {
return (Double) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Double) getEmptyValue(ctxt);
}
// fall through to coerce
case JsonTokenId.ID_NUMBER_FLOAT: // safe coercion
return p.getDoubleValue();
// 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
case JsonTokenId.ID_START_OBJECT:
text = ctxt.extractScalarFromObject(p, this, _valueClass);
break;
case JsonTokenId.ID_START_ARRAY:
return _deserializeFromArray(p, ctxt);
default:
return (Double) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
// 18-Nov-2020, tatu: Special case, Not-a-Numbers as String need to be
// considered "native" representation as JSON does not allow as numbers,
// and hence not bound by coercion rules
{
Double nan = this._checkDoubleSpecialValue(text);
if (nan != null) {
return nan;
}
}
// Coercion from String most complicated
final CoercionAction act = _checkFromStringCoercion(ctxt, text);
if (act == CoercionAction.AsNull) {
return (Double) getNullValue(ctxt);
}
if (act == CoercionAction.AsEmpty) {
return (Double) getEmptyValue(ctxt);
}
text = text.trim();
if (_checkTextualNull(ctxt, text)) {
return (Double) getNullValue(ctxt);
}
// 09-Dec-2023, tatu: To avoid parser having to validate input, pre-validate:
if (NumberInput.looksLikeValidNumber(text)) {
p.streamReadConstraints().validateFPLength(text.length());
try {
return _parseDouble(text, p.isEnabled(StreamReadFeature.USE_FAST_DOUBLE_PARSER));
} catch (IllegalArgumentException iae) { }
}
return (Double) ctxt.handleWeirdStringValue(_valueClass, text,
"not a valid `Double` value");
}
}
/**
* For type Number.class
, we can just rely on type
* mappings that plain {@link JsonParser#getNumberValue} returns.
*
* There is one additional complication: some numeric
* types (specifically, int/Integer and double/Double) are "non-typed";
* meaning that they will NEVER be output with type information.
* But other numeric types may need such type information.
* This is why {@link #deserializeWithType} must be overridden.
*/
@SuppressWarnings("serial")
@JacksonStdImpl
public static class NumberDeserializer
extends StdScalarDeserializer