Skip to content

Commit

Permalink
refactoring for coercion fails
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Mar 14, 2017
1 parent 7ce17ac commit 2f1582c
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 106 deletions.
Expand Up @@ -164,52 +164,6 @@ public final T getNullValue(DeserializationContext ctxt) throws JsonMappingExcep
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
return _emptyValue;
}

/**
* Method to call when JSON `null` token is encountered. Note: only called when
* this deserializer encounters it but NOT when reached via property
*
* @since 2.9
*/
protected Object _coerceNull(DeserializationContext ctxt) throws JsonMappingException
{
if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map `null` into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
handledType().toString());
}
return _nullValue;
}

/**
* Method called when JSON String with value "null" is encountered.
*
* @since 2.9
*/
protected Object _coerceTextualNull(DeserializationContext ctxt) throws JsonMappingException
{
if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map String \"null\" into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
handledType().toString());
}
return _nullValue;
}

/**
* Method called when JSON String with value "" (that is, zero length) is encountered.
*
* @since 2.9
*/
protected Object _coerceEmptyString(DeserializationContext ctxt) throws JsonMappingException
{
if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map empty String (\"\") into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
handledType().toString());
}
return _nullValue;
}
}

/*
Expand Down Expand Up @@ -263,7 +217,7 @@ protected final Boolean _parseBoolean(JsonParser p, DeserializationContext ctxt)
return Boolean.valueOf(_parseBooleanFromInt(p, ctxt));
}
if (t == JsonToken.VALUE_NULL) {
return (Boolean) _coerceNull(ctxt);
return (Boolean) _coerceNullToken(ctxt, _primitive);
}
// And finally, let's allow Strings to be converted too
if (t == JsonToken.VALUE_STRING) {
Expand All @@ -276,10 +230,10 @@ protected final Boolean _parseBoolean(JsonParser p, DeserializationContext ctxt)
return Boolean.FALSE;
}
if (text.length() == 0) {
return (Boolean) _coerceEmptyString(ctxt);
return (Boolean) _coerceEmptyString(ctxt, _primitive);
}
if (_hasTextualNull(text)) {
return (Boolean) _coerceTextualNull(ctxt);
return (Boolean) _coerceTextualNull(ctxt, _primitive);
}
return (Boolean) ctxt.handleWeirdStringValue(_valueClass, text,
"only \"true\" or \"false\" recognized");
Expand Down Expand Up @@ -328,13 +282,13 @@ protected Byte _parseByte(JsonParser p, DeserializationContext ctxt) throws IOEx
if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
String text = p.getText().trim();
if (_hasTextualNull(text)) {
return (Byte) _coerceTextualNull(ctxt);
return (Byte) _coerceTextualNull(ctxt, _primitive);
}
int value;
try {
int len = text.length();
if (len == 0) {
return (Byte) _coerceEmptyString(ctxt);
return (Byte) _coerceEmptyString(ctxt, _primitive);
}
value = NumberInput.parseInt(text);
} catch (IllegalArgumentException iae) {
Expand All @@ -357,7 +311,7 @@ protected Byte _parseByte(JsonParser p, DeserializationContext ctxt) throws IOEx
return p.getByteValue();
}
if (t == JsonToken.VALUE_NULL) {
return (Byte) _coerceNull(ctxt);
return (Byte) _coerceNullToken(ctxt, _primitive);
}
// [databind#381]
if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
Expand Down Expand Up @@ -406,10 +360,10 @@ protected Short _parseShort(JsonParser p, DeserializationContext ctxt) throws IO
try {
int len = text.length();
if (len == 0) {
return (Short) _coerceEmptyString(ctxt);
return (Short) _coerceEmptyString(ctxt, _primitive);
}
if (_hasTextualNull(text)) {
return (Short) _coerceTextualNull(ctxt);
return (Short) _coerceTextualNull(ctxt, _primitive);
}
value = NumberInput.parseInt(text);
} catch (IllegalArgumentException iae) {
Expand All @@ -430,7 +384,7 @@ protected Short _parseShort(JsonParser p, DeserializationContext ctxt) throws IO
return p.getShortValue();
}
if (t == JsonToken.VALUE_NULL) {
return (Short) _coerceNull(ctxt);
return (Short) _coerceNullToken(ctxt, _primitive);
}
// [databind#381]
if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
Expand Down Expand Up @@ -479,11 +433,11 @@ public Character deserialize(JsonParser p, DeserializationContext ctxt)
}
// actually, empty should become null?
if (text.length() == 0) {
return (Character) _coerceEmptyString(ctxt);
return (Character) _coerceEmptyString(ctxt, _primitive);
}
break;
case JsonTokenId.ID_NULL:
return (Character) _coerceNull(ctxt);
return (Character) _coerceNullToken(ctxt, _primitive);
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
Expand Down Expand Up @@ -552,7 +506,7 @@ protected final Integer _parseInteger(JsonParser p, DeserializationContext ctxt)
try {
int len = text.length();
if (_hasTextualNull(text)) {
return (Integer) _coerceTextualNull(ctxt);
return (Integer) _coerceTextualNull(ctxt, _primitive);
}
if (len > 9) {
long l = Long.parseLong(text);
Expand All @@ -564,15 +518,15 @@ protected final Integer _parseInteger(JsonParser p, DeserializationContext ctxt)
return Integer.valueOf((int) l);
}
if (len == 0) {
return (Integer) _coerceEmptyString(ctxt);
return (Integer) _coerceEmptyString(ctxt, _primitive);
}
return Integer.valueOf(NumberInput.parseInt(text));
} catch (IllegalArgumentException iae) {
return (Integer) ctxt.handleWeirdStringValue(_valueClass, text,
"not a valid Integer value");
}
case JsonTokenId.ID_NULL:
return (Integer) _coerceNull(ctxt);
return (Integer) _coerceNullToken(ctxt, _primitive);
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
Expand Down Expand Up @@ -630,10 +584,10 @@ protected final Long _parseLong(JsonParser p, DeserializationContext ctxt) throw
// !!! 05-Jan-2009, tatu: Should we try to limit value space, JDK is too lenient?
String text = p.getText().trim();
if (text.length() == 0) {
return (Long) _coerceEmptyString(ctxt);
return (Long) _coerceEmptyString(ctxt, _primitive);
}
if (_hasTextualNull(text)) {
return (Long) _coerceTextualNull(ctxt);
return (Long) _coerceTextualNull(ctxt, _primitive);
}
try {
return Long.valueOf(NumberInput.parseLong(text));
Expand All @@ -642,7 +596,7 @@ protected final Long _parseLong(JsonParser p, DeserializationContext ctxt) throw
"not a valid Long value");
// fall-through
case JsonTokenId.ID_NULL:
return (Long) _coerceNull(ctxt);
return (Long) _coerceNullToken(ctxt, _primitive);
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
Expand Down Expand Up @@ -692,10 +646,10 @@ protected final Float _parseFloat(JsonParser p, DeserializationContext ctxt)
if (t == JsonToken.VALUE_STRING) {
String text = p.getText().trim();
if ((text.length() == 0)) {
return (Float) _coerceEmptyString(ctxt);
return (Float) _coerceEmptyString(ctxt, _primitive);
}
if (_hasTextualNull(text)) {
return (Float) _coerceTextualNull(ctxt);
return (Float) _coerceTextualNull(ctxt, _primitive);
}
switch (text.charAt(0)) {
case 'I':
Expand All @@ -721,7 +675,7 @@ protected final Float _parseFloat(JsonParser p, DeserializationContext ctxt)
"not a valid Float value");
}
if (t == JsonToken.VALUE_NULL) {
return (Float) _coerceNull(ctxt);
return (Float) _coerceNullToken(ctxt, _primitive);
}
if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
Expand Down Expand Up @@ -774,10 +728,10 @@ protected final Double _parseDouble(JsonParser p, DeserializationContext ctxt) t
if (t == JsonToken.VALUE_STRING) {
String text = p.getText().trim();
if ((text.length() == 0)) {
return (Double) _coerceEmptyString(ctxt);
return (Double) _coerceEmptyString(ctxt, _primitive);
}
if (_hasTextualNull(text)) {
return (Double) _coerceTextualNull(ctxt);
return (Double) _coerceTextualNull(ctxt, _primitive);
}
switch (text.charAt(0)) {
case 'I':
Expand All @@ -803,7 +757,7 @@ protected final Double _parseDouble(JsonParser p, DeserializationContext ctxt) t
"not a valid Double value");
}
if (t == JsonToken.VALUE_NULL) {
return (Double) _coerceNull(ctxt);
return (Double) _coerceNullToken(ctxt, _primitive);
}
if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
Expand Down
Expand Up @@ -567,6 +567,32 @@ protected final boolean _isPosInf(String text) {
/****************************************************
*/

protected void _failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt,
String type) throws IOException
{
ctxt.reportInputMismatch(handledType(),
"Can not coerce a floating-point value ('%s') into %s; enable `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to allow",
p.getValueAsString(), type);
}

protected final void _verifyPrimitiveNull(DeserializationContext ctxt) throws IOException
{
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map `null` as %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
_coercedTypeDesc());
}
}

protected final void _verifyPrimitiveNullCoercion(DeserializationContext ctxt, String str) throws IOException
{
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map String \"%s\" as %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
str, _coercedTypeDesc());
}
}

/**
* Helper method called in case where an integral number is encountered, but
* config settings suggest that a coercion may be needed to "upgrade"
Expand All @@ -590,6 +616,79 @@ protected Object _coerceIntegral(JsonParser p, DeserializationContext ctxt) thro
return p.getBigIntegerValue(); // should be optimal, whatever it is
}

/**
* Method to call when JSON `null` token is encountered. Note: only called when
* this deserializer encounters it but NOT when reached via property
*
* @since 2.9
*/
protected Object _coerceNullToken(DeserializationContext ctxt, boolean isPrimitive) throws JsonMappingException
{
if (isPrimitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map `null` as %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
_coercedTypeDesc());
}
return getNullValue(ctxt);
}

/**
* Method called when JSON String with value "null" is encountered.
*
* @since 2.9
*/
protected Object _coerceTextualNull(DeserializationContext ctxt, boolean isPrimitive) throws JsonMappingException
{
if (isPrimitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map String \"null\" as %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
_coercedTypeDesc());
}
return getNullValue(ctxt);
}

/**
* Method called when JSON String with value "" (that is, zero length) is encountered.
*
* @since 2.9
*/
protected Object _coerceEmptyString(DeserializationContext ctxt, boolean isPrimitive) throws JsonMappingException
{
if (isPrimitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map empty String (\"\") as %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
_coercedTypeDesc());
}
return getNullValue(ctxt);
}

/**
* Helper method called to get a description of type into which a scalar value coercion
* is (most likely) being applied, to be used for constructing exception messages
* on coerce failure.
*
* @since 2.9
*/
protected String _coercedTypeDesc() {
boolean structured;
String typeDesc;

JavaType t = getValueType();
if (t != null) {
structured = (t.isContainerType() || t.isReferenceType());
typeDesc = t.toString();
} else {
Class<?> cls = handledType();
structured = cls.isArray() || Collection.class.isAssignableFrom(cls)
|| Map.class.isAssignableFrom(cls);
typeDesc = cls.getSimpleName();
}
if (structured) {
return "contents of type "+typeDesc;
}
return "value of type "+typeDesc;
}

/*
/****************************************************
/* Helper methods for sub-classes, resolving dependencies
Expand Down Expand Up @@ -861,33 +960,6 @@ protected void handleMissingEndArrayForSingle(JsonParser p, DeserializationConte
// but for now just fall through
}

protected void _failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt,
String type) throws IOException
{
ctxt.reportInputMismatch(handledType(),
"Can not coerce a floating-point value ('%s') into %s; enable `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to allow",
p.getValueAsString(), type);
}

protected final void _verifyPrimitiveNull(DeserializationContext ctxt) throws IOException
{
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map `null` into primitive contents of type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
handledType().getSimpleName());
}
}

protected final void _verifyPrimitiveNullCoercion(DeserializationContext ctxt, String str) throws IOException
{
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
ctxt.reportInputMismatch(this,
"Can not map String \"%s\" into primitive contents of type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)",
str,
handledType().getSimpleName());
}
}

protected void _verifyEndArrayForSingle(JsonParser p, DeserializationContext ctxt) throws IOException
{
JsonToken t = p.nextToken();
Expand Down

0 comments on commit 2f1582c

Please sign in to comment.