aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tatu.saloranta@iki.fi>2020-06-13 08:51:15 -0700
committerTatu Saloranta <tatu.saloranta@iki.fi>2020-06-13 08:51:15 -0700
commitc305e60b1a4135933fed9ee5890b9ffc17db7dd0 (patch)
treeac934ea2c414642f98d27f62e85dd0895df6141c
parentab062794ec320de045fa64751b55f5fa4fe44a9f (diff)
downloadjackson-databind-c305e60b1a4135933fed9ee5890b9ffc17db7dd0.tar.gz
last coercions (float, double), before rearranging
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java22
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java8
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java74
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java52
4 files changed, 72 insertions, 84 deletions
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 6c02d8284..7cba05f7c 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
@@ -450,6 +450,9 @@ public class NumberDeserializers
@Override
public Float deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
+ if (_primitive) {
+ return _parseFloatPrimitive(ctxt, p);
+ }
return _parseFloat(p, ctxt);
}
@@ -457,9 +460,11 @@ public class NumberDeserializers
throws IOException
{
// We accept couple of different types; obvious ones first:
- JsonToken t = p.currentToken();
-
- if (t == JsonToken.VALUE_NUMBER_FLOAT || t == JsonToken.VALUE_NUMBER_INT) { // coercing should work too
+ if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
+ return p.getFloatValue();
+ }
+ final JsonToken t = p.currentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT) { // safe coercion
return p.getFloatValue();
}
// And finally, let's allow Strings to be converted too
@@ -534,13 +539,20 @@ public class NumberDeserializers
public Double deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer) throws IOException
{
+ if (_primitive) {
+ return _parseDoublePrimitive(ctxt, p);
+ }
return _parseDouble(p, ctxt);
}
protected final Double _parseDouble(JsonParser p, DeserializationContext ctxt) throws IOException
{
- JsonToken t = p.currentToken();
- if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) { // coercing should work too
+ // We accept couple of different types; obvious ones first:
+ if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
+ return p.getDoubleValue();
+ }
+ final JsonToken t = p.currentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT) { // safe coercion
return p.getDoubleValue();
}
if (t == JsonToken.VALUE_STRING) {
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 bbff390e8..657d2de74 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
@@ -830,7 +830,7 @@ public abstract class PrimitiveArrayDeserializers<T> extends StdDeserializer<T>
continue;
}
}
- float value = _parseFloatPrimitive(p, ctxt);
+ float value = _parseFloatPrimitive(ctxt, p);
if (ix >= chunk.length) {
chunk = builder.appendCompletedChunk(chunk, ix);
ix = 0;
@@ -846,7 +846,7 @@ public abstract class PrimitiveArrayDeserializers<T> extends StdDeserializer<T>
@Override
protected float[] handleSingleElementUnwrapped(JsonParser p,
DeserializationContext ctxt) throws IOException {
- return new float[] { _parseFloatPrimitive(p, ctxt) };
+ return new float[] { _parseFloatPrimitive(ctxt, p) };
}
@Override
@@ -900,7 +900,7 @@ public abstract class PrimitiveArrayDeserializers<T> extends StdDeserializer<T>
continue;
}
}
- double value = _parseDoublePrimitive(p, ctxt);
+ double value = _parseDoublePrimitive(ctxt, p);
if (ix >= chunk.length) {
chunk = builder.appendCompletedChunk(chunk, ix);
ix = 0;
@@ -916,7 +916,7 @@ public abstract class PrimitiveArrayDeserializers<T> extends StdDeserializer<T>
@Override
protected double[] handleSingleElementUnwrapped(JsonParser p,
DeserializationContext ctxt) throws IOException {
- return new double[] { _parseDoublePrimitive(p, ctxt) };
+ return new double[] { _parseDoublePrimitive(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 fd9e6d4cc..13f7b660c 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
@@ -978,29 +978,43 @@ public abstract class StdDeserializer<T>
return (Long) ctxt.handleUnexpectedToken(ctxt.constructType(targetType), p);
}
+ @Deprecated // since 2.12, use overloaded variant
protected final float _parseFloatPrimitive(JsonParser p, DeserializationContext ctxt)
+ throws IOException {
+ return _parseFloatPrimitive(ctxt, p);
+ }
+
+ protected final float _parseFloatPrimitive(DeserializationContext ctxt, JsonParser p)
throws IOException
{
- if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
- return p.getFloatValue();
- }
+ CoercionAction act;
switch (p.currentTokenId()) {
- case JsonTokenId.ID_STRING:
- String text = p.getText().trim();
- if (_isEmptyOrTextualNull(text)) {
- _verifyNullForPrimitiveCoercion(ctxt, text);
- return 0.0f;
- }
- return _parseFloatPrimitive(ctxt, text);
case JsonTokenId.ID_NUMBER_INT:
+ case JsonTokenId.ID_NUMBER_FLOAT:
return p.getFloatValue();
case JsonTokenId.ID_NULL:
_verifyNullForPrimitive(ctxt);
- return 0.0f;
+ return 0f;
+ case JsonTokenId.ID_STRING:
+ String text = p.getText();
+ act = _checkFromStringCoercion(ctxt, text,
+ LogicalType.Integer, Float.TYPE);
+ if (act == CoercionAction.AsNull) {
+ return 0.0f; // no need to check as does not come from `null`, explicit coercion
+ }
+ if (act == CoercionAction.AsEmpty) {
+ return 0.0f;
+ }
+ text = text.trim();
+ if (_hasTextualNull(text)) {
+ _verifyNullForPrimitiveCoercion(ctxt, text);
+ return 0.0f;
+ }
+ return _parseFloatPrimitive(ctxt, text);
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
- final float parsed = _parseFloatPrimitive(p, ctxt);
+ final float parsed = _parseFloatPrimitive(ctxt, p);
_verifyEndArrayForSingle(p, ctxt);
return parsed;
}
@@ -1039,29 +1053,43 @@ public abstract class StdDeserializer<T>
return _nonNullNumber(v).floatValue();
}
+ @Deprecated // since 2.12, use overloaded variant
protected final double _parseDoublePrimitive(JsonParser p, DeserializationContext ctxt)
+ throws IOException {
+ return _parseDoublePrimitive(ctxt, p);
+ }
+
+ protected final double _parseDoublePrimitive(DeserializationContext ctxt, JsonParser p)
throws IOException
{
- if (p.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) {
- return p.getDoubleValue();
- }
+ CoercionAction act;
switch (p.currentTokenId()) {
- case JsonTokenId.ID_STRING:
- String text = p.getText().trim();
- if (_isEmptyOrTextualNull(text)) {
- _verifyNullForPrimitiveCoercion(ctxt, text);
- return 0.0;
- }
- return _parseDoublePrimitive(ctxt, text);
case JsonTokenId.ID_NUMBER_INT:
+ case JsonTokenId.ID_NUMBER_FLOAT:
return p.getDoubleValue();
case JsonTokenId.ID_NULL:
_verifyNullForPrimitive(ctxt);
return 0.0;
+ case JsonTokenId.ID_STRING:
+ String text = p.getText();
+ act = _checkFromStringCoercion(ctxt, text,
+ LogicalType.Integer, Double.TYPE);
+ if (act == CoercionAction.AsNull) {
+ return 0.0; // no need to check as does not come from `null`, explicit coercion
+ }
+ if (act == CoercionAction.AsEmpty) {
+ return 0.0;
+ }
+ text = text.trim();
+ if (_hasTextualNull(text)) {
+ _verifyNullForPrimitiveCoercion(ctxt, text);
+ return 0.0;
+ }
+ return _parseDoublePrimitive(ctxt, text);
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
- final double parsed = _parseDoublePrimitive(p, ctxt);
+ final double parsed = _parseDoublePrimitive(ctxt, p);
_verifyEndArrayForSingle(p, ctxt);
return parsed;
}
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 d4111686d..93bddb0fa 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
@@ -541,31 +541,6 @@ public class JDKScalarsTest
/**********************************************************
*/
- 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(double.class, Double.valueOf(0.0));
- _testEmptyToNullCoercion(float.class, Float.valueOf(0.0f));
- }
-
- private void _testEmptyToNullCoercion(Class<?> primType, Object emptyValue) throws Exception
- {
- final String EMPTY = "\"\"";
-
- // as per [databind#1095] should only allow coercion from empty String,
- // if `null` is acceptable
- ObjectReader intR = MAPPER.readerFor(primType);
- assertEquals(emptyValue, intR.readValue(EMPTY));
- try {
- intR.with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
- .readValue("\"\"");
- fail("Should not have passed");
- } catch (MismatchedInputException e) {
- verifyException(e, "Cannot map `null` into type ");
- }
- }
-
public void testBase64Variants() throws Exception
{
final byte[] INPUT = "abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890X".getBytes("UTF-8");
@@ -700,33 +675,6 @@ public class JDKScalarsTest
}
}
- public void testEmptyStringFailForPrimitives() throws IOException
- {
- // 12-Jun-2020, tatu: Empty String coercion is not same as explicit
- // `null`, so some of these do not apply:
-// _verifyEmptyStringFailForPrimitives("byteValue");
- _verifyEmptyStringFailForPrimitives("charValue");
-// _verifyEmptyStringFailForPrimitives("shortValue");
-// _verifyEmptyStringFailForPrimitives("intValue");
-// _verifyEmptyStringFailForPrimitives("longValue");
- _verifyEmptyStringFailForPrimitives("floatValue");
- _verifyEmptyStringFailForPrimitives("doubleValue");
- }
-
- private void _verifyEmptyStringFailForPrimitives(String propName) throws IOException
- {
- final ObjectReader reader = MAPPER
- .readerFor(PrimitivesBean.class)
- .with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
- try {
- reader.readValue(aposToQuotes("{'"+propName+"':''}"));
- fail("Expected failure for '"+propName+"' + empty String");
- } catch (JsonMappingException e) {
- verifyException(e, "Cannot map `null` into type");
- verifyException(e, "FAIL_ON_NULL_FOR_PRIMITIVES");
- }
- }
-
/*
/**********************************************************
/* Null handling for scalars in POJO