diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java index cae6bac432..72fc6924f5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java @@ -6,7 +6,6 @@ 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; @@ -407,46 +406,10 @@ public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOExce if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { return p.getLongValue(); } - return _parseLong(p, ctxt); - } - - protected final Long _parseLong(JsonParser p, DeserializationContext ctxt) throws IOException - { - switch (p.currentTokenId()) { - // NOTE: caller assumed to usually check VALUE_NUMBER_INT in fast path - case JsonTokenId.ID_NUMBER_INT: - return p.getLongValue(); - case JsonTokenId.ID_NUMBER_FLOAT: - if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) { - _failDoubleToIntCoercion(p, ctxt, "Long"); - } - return p.getValueAsLong(); - case JsonTokenId.ID_STRING: - String text = p.getText(); - CoercionAction act = _checkFromStringCoercion(ctxt, text); - if (act == CoercionAction.AsNull) { - return (Long) getNullValue(ctxt); - } - if (act == CoercionAction.AsEmpty) { - return (Long) getEmptyValue(ctxt); - } - text = text.trim(); - if (_hasTextualNull(text)) { - return (Long) _coerceTextualNull(ctxt, _primitive); - } - // let's allow Strings to be converted too - try { - return Long.valueOf(NumberInput.parseLong(text)); - } catch (IllegalArgumentException iae) { } - return (Long) ctxt.handleWeirdStringValue(_valueClass, text, - "not a valid Long value"); - case JsonTokenId.ID_NULL: - return (Long) _coerceNullToken(ctxt, _primitive); - case JsonTokenId.ID_START_ARRAY: - return _deserializeFromArray(p, ctxt); + if (_primitive) { + return _parseLongPrimitive(ctxt, p); } - // Otherwise, no can do: - return (Long) ctxt.handleUnexpectedToken(getValueType(ctxt), p); + return _parseLong(ctxt, p, _valueClass); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java index bf538f637b..f196254582 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java @@ -736,7 +736,7 @@ public long[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx _verifyNullForPrimitive(ctxt); value = 0L; } else { - value = _parseLongPrimitive(p, ctxt); + value = _parseLongPrimitive(ctxt, p); } if (ix >= chunk.length) { chunk = builder.appendCompletedChunk(chunk, ix); @@ -753,7 +753,7 @@ public long[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx @Override protected long[] handleSingleElementUnwrapped(JsonParser p, DeserializationContext ctxt) throws IOException { - return new long[] { _parseLongPrimitive(p, ctxt) }; + return new long[] { _parseLongPrimitive(ctxt, p) }; } @Override diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java index c21ae72604..a32a5217d9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java @@ -641,10 +641,10 @@ protected Short _parseShort(DeserializationContext ctxt, JsonParser p, return (Short) ctxt.handleUnexpectedToken(ctxt.constructType(targetType), p); } -// @Deprecated // since 2.12, use overloaded variant -// protected final short _parseIntPrimitive(JsonParser p, DeserializationContext ctxt) throws IOException { -// return _parseIntPrimitive(ctxt, p); -// } + @Deprecated // since 2.12, use overloaded variant + protected final int _parseIntPrimitive(JsonParser p, DeserializationContext ctxt) throws IOException { + return _parseIntPrimitive(ctxt, p); + } protected final int _parseIntPrimitive(DeserializationContext ctxt, JsonParser p) throws IOException @@ -716,11 +716,6 @@ protected final int _parseIntPrimitive(DeserializationContext ctxt, String text) } } - @Deprecated // since 2.12, use overloaded variant - protected final Integer _parseInteger(JsonParser p, DeserializationContext ctxt) throws IOException { - return _parseInteger(ctxt, p, _valueClass); - } - // @since 2.12 protected final Integer _parseInteger(DeserializationContext ctxt, JsonParser p, Class targetType) throws IOException @@ -778,36 +773,56 @@ protected final Integer _parseInteger(DeserializationContext ctxt, JsonParser p, return (Integer) ctxt.handleUnexpectedToken(ctxt.constructType(targetType), p); } + @Deprecated // since 2.12, use overloaded variant protected final long _parseLongPrimitive(JsonParser p, DeserializationContext ctxt) - throws IOException + throws IOException { + return _parseLongPrimitive(ctxt, p); + } + + protected final long _parseLongPrimitive(DeserializationContext ctxt, JsonParser p) + throws IOException { - if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { - return p.getLongValue(); - } + CoercionAction act; switch (p.currentTokenId()) { + case JsonTokenId.ID_NUMBER_INT: + return p.getLongValue(); + case JsonTokenId.ID_NULL: + _verifyNullForPrimitive(ctxt); + return 0L; case JsonTokenId.ID_STRING: - String text = p.getText().trim(); - if (_isEmptyOrTextualNull(text)) { + String text = p.getText(); + act = _checkFromStringCoercion(ctxt, text, + LogicalType.Integer, Long.TYPE); + if (act == CoercionAction.AsNull) { + return 0L; // no need to check as does not come from `null`, explicit coercion + } + if (act == CoercionAction.AsEmpty) { + return 0L; + } + text = text.trim(); + if (_hasTextualNull(text)) { _verifyNullForPrimitiveCoercion(ctxt, text); return 0L; } return _parseLongPrimitive(ctxt, text); case JsonTokenId.ID_NUMBER_FLOAT: - if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) { - _failDoubleToIntCoercion(p, ctxt, "long"); + act = _checkFloatToIntCoercion(ctxt, p, Integer.TYPE); + if (act == CoercionAction.AsNull) { + return 0L; + } + if (act == CoercionAction.AsEmpty) { + return 0L; } return p.getValueAsLong(); - case JsonTokenId.ID_NULL: - _verifyNullForPrimitive(ctxt); - return 0L; case JsonTokenId.ID_START_ARRAY: if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { p.nextToken(); - final long parsed = _parseLongPrimitive(p, ctxt); + final long parsed = _parseLongPrimitive(ctxt, p); _verifyEndArrayForSingle(p, ctxt); return parsed; } break; + default: } return ((Number) ctxt.handleUnexpectedToken(getValueType(ctxt), p)).longValue(); } @@ -824,6 +839,53 @@ protected final long _parseLongPrimitive(DeserializationContext ctxt, String tex } } + // @since 2.12 + protected final Long _parseLong(DeserializationContext ctxt, JsonParser p, + Class targetType) throws IOException + { + CoercionAction act; + switch (p.currentTokenId()) { + // NOTE: caller assumed to usually check VALUE_NUMBER_INT in fast path + case JsonTokenId.ID_NUMBER_INT: + return p.getLongValue(); + case JsonTokenId.ID_NULL: + return (Long) _coerceNullToken(ctxt, false); + case JsonTokenId.ID_STRING: + String text = p.getText(); + act = _checkFromStringCoercion(ctxt, text, + LogicalType.Integer, targetType); + if (act == CoercionAction.AsNull) { + return (Long) getNullValue(ctxt); + } + if (act == CoercionAction.AsEmpty) { + return (Long) getEmptyValue(ctxt); + } + text = text.trim(); + if (_hasTextualNull(text)) { + return (Long) _coerceTextualNull(ctxt, false); + } + // let's allow Strings to be converted too + try { + return Long.valueOf(NumberInput.parseLong(text)); + } catch (IllegalArgumentException iae) { } + return (Long) ctxt.handleWeirdStringValue(targetType, text, + "not a valid Long value"); + case JsonTokenId.ID_NUMBER_FLOAT: + act = _checkFloatToIntCoercion(ctxt, p, targetType); + if (act == CoercionAction.AsNull) { + return (Long) getNullValue(ctxt); + } + if (act == CoercionAction.AsEmpty) { + return (Long) getEmptyValue(ctxt); + } + return p.getValueAsLong(); + case JsonTokenId.ID_START_ARRAY: + return (Long) _deserializeFromArray(p, ctxt); + } + // Otherwise, no can do: + return (Long) ctxt.handleUnexpectedToken(ctxt.constructType(targetType), p); + } + protected final float _parseFloatPrimitive(JsonParser p, DeserializationContext ctxt) throws IOException { diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java index 05a90a11ab..e1870550a0 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java @@ -553,7 +553,7 @@ public void testFloatPrimitiveNonNumeric() throws Exception public void testEmptyToNullCoercionForPrimitives() throws Exception { // 12-Jun-2020, tatu: Not valid any more, null <> empty String // _testEmptyToNullCoercion(int.class, Integer.valueOf(0)); - _testEmptyToNullCoercion(long.class, Long.valueOf(0)); +// _testEmptyToNullCoercion(long.class, Long.valueOf(0)); _testEmptyToNullCoercion(double.class, Double.valueOf(0.0)); _testEmptyToNullCoercion(float.class, Float.valueOf(0.0f)); } @@ -717,7 +717,7 @@ public void testEmptyStringFailForPrimitives() throws IOException _verifyEmptyStringFailForPrimitives("charValue"); // _verifyEmptyStringFailForPrimitives("shortValue"); // _verifyEmptyStringFailForPrimitives("intValue"); - _verifyEmptyStringFailForPrimitives("longValue"); +// _verifyEmptyStringFailForPrimitives("longValue"); _verifyEmptyStringFailForPrimitives("floatValue"); _verifyEmptyStringFailForPrimitives("doubleValue"); }