aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tatu.saloranta@iki.fi>2020-06-09 23:25:44 -0700
committerTatu Saloranta <tatu.saloranta@iki.fi>2020-06-09 23:25:44 -0700
commit9f7103befdea1d2660f313e1b6a9044afded4a0d (patch)
tree9ee7c477cd23684101762a6437fa258947a857fe
parent0b66b20294095a8e2d8d9aabba9eb984e6c5dac1 (diff)
downloadjackson-databind-9f7103befdea1d2660f313e1b6a9044afded4a0d.tar.gz
Rewrote handling of "empty array to null" coercion, using CoercionConfigs (needs more testing)
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java35
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java35
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java78
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);
}
/*