diff options
author | Tatu Saloranta <tatu.saloranta@iki.fi> | 2020-06-13 08:51:15 -0700 |
---|---|---|
committer | Tatu Saloranta <tatu.saloranta@iki.fi> | 2020-06-13 08:51:15 -0700 |
commit | c305e60b1a4135933fed9ee5890b9ffc17db7dd0 (patch) | |
tree | ac934ea2c414642f98d27f62e85dd0895df6141c | |
parent | ab062794ec320de045fa64751b55f5fa4fe44a9f (diff) | |
download | jackson-databind-c305e60b1a4135933fed9ee5890b9ffc17db7dd0.tar.gz |
last coercions (float, double), before rearranging
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 |