diff options
author | Tatu Saloranta <tatu.saloranta@iki.fi> | 2020-06-09 23:25:44 -0700 |
---|---|---|
committer | Tatu Saloranta <tatu.saloranta@iki.fi> | 2020-06-09 23:25:44 -0700 |
commit | 9f7103befdea1d2660f313e1b6a9044afded4a0d (patch) | |
tree | 9ee7c477cd23684101762a6437fa258947a857fe | |
parent | 0b66b20294095a8e2d8d9aabba9eb984e6c5dac1 (diff) | |
download | jackson-databind-9f7103befdea1d2660f313e1b6a9044afded4a0d.tar.gz |
Rewrote handling of "empty array to null" coercion, using CoercionConfigs (needs more testing)
3 files changed, 85 insertions, 63 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java index e94891ac4..ced28f0a9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java @@ -5,6 +5,7 @@ import java.util.*; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CoercionAction; import com.fasterxml.jackson.databind.deser.impl.*; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring; import com.fasterxml.jackson.databind.util.NameTransformer; @@ -583,23 +584,29 @@ public class BeanDeserializer } return bean; } - if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { - JsonToken t = p.nextToken(); - if (t == JsonToken.END_ARRAY && ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { - return null; - } - final Object value = deserialize(p, ctxt); - if (p.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(p, ctxt); - } - return value; - } - if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { + final CoercionAction act = _findCoercionFromEmptyArray(ctxt); + final boolean unwrap = ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); + + if (unwrap || (act != CoercionAction.Fail)) { JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { - return null; + switch (act) { + case AsEmpty: + return getEmptyValue(ctxt); + case AsNull: + case TryConvert: + return getNullValue(ctxt); + default: + } + return ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null); + } + if (unwrap) { + final Object value = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); + } + return value; } - return ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null); } return ctxt.handleUnexpectedToken(getValueType(ctxt), p); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java index 295de3179..fa15ed319 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java @@ -5,6 +5,7 @@ import java.util.*; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CoercionAction; import com.fasterxml.jackson.databind.deser.impl.*; import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; import com.fasterxml.jackson.databind.util.NameTransformer; @@ -492,23 +493,29 @@ public class BuilderBasedDeserializer } return finishBuild(ctxt, builder); } - if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { - JsonToken t = p.nextToken(); - if (t == JsonToken.END_ARRAY && ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { - return null; - } - final Object value = deserialize(p, ctxt); - if (p.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(p, ctxt); - } - return value; - } - if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { + final CoercionAction act = _findCoercionFromEmptyArray(ctxt); + final boolean unwrap = ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); + + if (unwrap || (act != CoercionAction.Fail)) { JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { - return null; + switch (act) { + case AsEmpty: + return getEmptyValue(ctxt); + case AsNull: + case TryConvert: + return getNullValue(ctxt); + default: + } + return ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null); + } + if (unwrap) { + final Object value = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); + } + return value; } - return ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null); } return ctxt.handleUnexpectedToken(getValueType(ctxt), p); } 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 3f88e9430..c575dd65b 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 @@ -51,12 +51,11 @@ public abstract class StdDeserializer<T> DeserializationFeature.USE_BIG_INTEGER_FOR_INTS.getMask() | DeserializationFeature.USE_LONG_FOR_INTS.getMask(); - // @since 2.9 + @Deprecated // since 2.12 protected final static int F_MASK_ACCEPT_ARRAYS = DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS.getMask() | DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT.getMask(); - /** * Type of values this deserializer handles: sometimes * exact types, other time most specific supertype of @@ -179,11 +178,11 @@ public abstract class StdDeserializer<T> */ /** - * Helper method that allows easy support for array-related {@link DeserializationFeature}s - * `ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT` and `UNWRAP_SINGLE_VALUE_ARRAYS`: checks for either - * empty array, or single-value array-wrapped value (respectively), and either reports - * an exception (if no match, or feature(s) not enabled), or returns appropriate - * result value. + * Helper method that allows easy support for array-related coercion features: + * checks for either empty array, or single-value array-wrapped value (if coercion + * enabled by {@code CoercionConfigs} (since 2.12), and either reports + * an exception (if no coercion allowed), or returns appropriate + * result value using coercion mechanism indicated. *<p> * This method should NOT be called if Array representation is explicitly supported * for type: it should only be called in case it is otherwise unrecognized. @@ -194,29 +193,32 @@ public abstract class StdDeserializer<T> * * @since 2.9 */ + @SuppressWarnings("unchecked") protected T _deserializeFromArray(JsonParser p, DeserializationContext ctxt) throws IOException { - JsonToken t; - if (ctxt.hasSomeOfFeatures(F_MASK_ACCEPT_ARRAYS)) { - t = p.nextToken(); + final CoercionAction act = _findCoercionFromEmptyArray(ctxt); + final boolean unwrap = ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); + + if (unwrap || (act != CoercionAction.Fail)) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { - if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { + switch (act) { + case AsEmpty: + return (T) getEmptyValue(ctxt); + case AsNull: + case TryConvert: return getNullValue(ctxt); + default: } - } - if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { + } else if (unwrap) { final T parsed = _deserializeWrappedValue(p, ctxt); if (p.nextToken() != JsonToken.END_ARRAY) { handleMissingEndArrayForSingle(p, ctxt); } return parsed; } - } else { - t = p.currentToken(); } - @SuppressWarnings("unchecked") - T result = (T) ctxt.handleUnexpectedToken(getValueType(ctxt), p.currentToken(), p, null); - return result; + return (T) ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null); } /** @@ -228,7 +230,7 @@ public abstract class StdDeserializer<T> * @deprecated Since 2.12 */ @SuppressWarnings("unchecked") - @Deprecated + @Deprecated // since 2.12 protected T _deserializeFromEmpty(JsonParser p, DeserializationContext ctxt) throws IOException { @@ -715,23 +717,27 @@ public abstract class StdDeserializer<T> protected java.util.Date _parseDateFromArray(JsonParser p, DeserializationContext ctxt) throws IOException { - JsonToken t; - if (ctxt.hasSomeOfFeatures(F_MASK_ACCEPT_ARRAYS)) { - t = p.nextToken(); + final CoercionAction act = _findCoercionFromEmptyArray(ctxt); + final boolean unwrap = ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); + + if (unwrap || (act != CoercionAction.Fail)) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { - if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { + switch (act) { + case AsEmpty: + return (java.util.Date) getEmptyValue(ctxt); + case AsNull: + case TryConvert: return (java.util.Date) getNullValue(ctxt); + default: } - } - if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { + } else if (unwrap) { final Date parsed = _parseDate(p, ctxt); _verifyEndArrayForSingle(p, ctxt); return parsed; } - } else { - t = p.currentToken(); } - return (java.util.Date) ctxt.handleUnexpectedToken(_valueClass, t, p, null); + return (java.util.Date) ctxt.handleUnexpectedToken(_valueClass, JsonToken.START_ARRAY, p, null); } /** @@ -1327,18 +1333,20 @@ value, _coercedTypeDesc()); // @since 2.12 protected CoercionAction _findCoercionFromEmptyString(DeserializationContext ctxt) { - final Class<?> targetClass = handledType(); - final LogicalType targetType = logicalType(); + return ctxt.findCoercionAction(logicalType(), handledType(), + CoercionInputShape.EmptyString); + } - return ctxt.findCoercionAction(targetType, targetClass, CoercionInputShape.EmptyString); + // @since 2.12 + protected CoercionAction _findCoercionFromEmptyArray(DeserializationContext ctxt) { + return ctxt.findCoercionAction(logicalType(), handledType(), + CoercionInputShape.EmptyArray); } // @since 2.12 protected CoercionAction _findCoercionFromBlankString(DeserializationContext ctxt) { - final Class<?> targetClass = handledType(); - final LogicalType targetType = logicalType(); - - return ctxt.findCoercionFromBlankString(targetType, targetClass, CoercionAction.Fail); + return ctxt.findCoercionFromBlankString(logicalType(), handledType(), + CoercionAction.Fail); } /* |