package com.fasterxml.jackson.databind.deser.std;
import java.io.
IOException;
import java.util.*;
import com.fasterxml.jackson.
core.*;
import com.fasterxml.jackson.
core.
JsonParser.
NumberType;
import com.fasterxml.jackson.
core.
io.
NumberInput;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.
annotation.
JacksonStdImpl;
import com.fasterxml.jackson.databind.
jsontype.
TypeDeserializer;
import com.fasterxml.jackson.databind.
util.
ClassUtil;
import com.fasterxml.jackson.databind.
util.
Converter;
/**
* Base class for common deserializers. Contains shared
* base functionality for dealing with primitive values, such
* as (re)parsing from String.
*/
public abstract class
StdDeserializer<T>
extends
JsonDeserializer<T>
implements java.io.
Serializable
{
private static final long
serialVersionUID = 1L;
/**
* Type of values this deserializer handles: sometimes
* exact types, other time most specific supertype of
* types deserializer handles (which may be as generic
* as {@link Object} in some case)
*/
final protected
Class<?>
_valueClass;
protected
StdDeserializer(
Class<?>
vc) {
_valueClass =
vc;
}
protected
StdDeserializer(
JavaType valueType) {
_valueClass = (
valueType == null) ? null :
valueType.
getRawClass();
}
/*
/**********************************************************
/* Accessors
/**********************************************************
*/
@
Override
public
Class<?>
handledType() {
return
_valueClass;
}
/*
/**********************************************************
/* Extended API
/**********************************************************
*/
/**
* @deprecated Since 2.3 use {@link #handledType} instead
*/
@
Deprecated
public final
Class<?>
getValueClass() { return
_valueClass; }
/**
* Exact structured type deserializer handles, if known.
*<p>
* Default implementation just returns null.
*/
public
JavaType getValueType() { return null; }
/**
* Method that can be called to determine if given deserializer is the default
* deserializer Jackson uses; as opposed to a custom deserializer installed by
* a module or calling application. Determination is done using
* {@link JacksonStdImpl} annotation on deserializer class.
*/
protected boolean isDefaultDeserializer(
JsonDeserializer<?>
deserializer) {
return
ClassUtil.
isJacksonStdImpl(
deserializer);
}
protected boolean isDefaultKeyDeserializer(
KeyDeserializer keyDeser) {
return
ClassUtil.
isJacksonStdImpl(
keyDeser);
}
/*
/**********************************************************
/* Partial JsonDeserializer implementation
/**********************************************************
*/
/**
* Base implementation that does not assume specific type
* inclusion mechanism. Sub-classes are expected to override
* this method if they are to handle type information.
*/
@
Override
public
Object deserializeWithType(
JsonParser jp,
DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws
IOException,
JsonProcessingException
{
return
typeDeserializer.
deserializeTypedFromAny(
jp,
ctxt);
}
/*
/**********************************************************
/* Helper methods for sub-classes, parsing: while mostly
/* useful for numeric types, can be also useful for dealing
/* with things serialized as numbers (such as Dates).
/**********************************************************
*/
protected final boolean _parseBooleanPrimitive(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_TRUE) {
return true;
}
if (
t ==
JsonToken.
VALUE_FALSE) {
return false;
}
if (
t ==
JsonToken.
VALUE_NULL) {
return false;
}
// [JACKSON-78]: should accept ints too, (0 == false, otherwise true)
if (
t ==
JsonToken.
VALUE_NUMBER_INT) {
// 11-Jan-2012, tatus: May be outside of int...
if (
jp.
getNumberType() ==
NumberType.
INT) {
return (
jp.
getIntValue() != 0);
}
return
_parseBooleanFromNumber(
jp,
ctxt);
}
// And finally, let's allow Strings to be converted too
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
// [#422]: Allow aliases
if ("true".
equals(
text) || "True".
equals(
text)) {
return true;
}
if ("false".
equals(
text) || "False".
equals(
text) ||
text.
length() == 0) {
return false;
}
if (
_hasTextualNull(
text)) {
return false;
}
throw
ctxt.
weirdStringException(
text,
_valueClass, "only \"true\" or \"false\" recognized");
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final
Boolean _parseBoolean(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_TRUE) {
return
Boolean.
TRUE;
}
if (
t ==
JsonToken.
VALUE_FALSE) {
return
Boolean.
FALSE;
}
// [JACKSON-78]: should accept ints too, (0 == false, otherwise true)
if (
t ==
JsonToken.
VALUE_NUMBER_INT) {
// 11-Jan-2012, tatus: May be outside of int...
if (
jp.
getNumberType() ==
NumberType.
INT) {
return (
jp.
getIntValue() == 0) ?
Boolean.
FALSE :
Boolean.
TRUE;
}
return
Boolean.
valueOf(
_parseBooleanFromNumber(
jp,
ctxt));
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Boolean)
getNullValue();
}
// And finally, let's allow Strings to be converted too
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
// [#422]: Allow aliases
if ("true".
equals(
text) || "True".
equals(
text)) {
return
Boolean.
TRUE;
}
if ("false".
equals(
text) || "False".
equals(
text)) {
return
Boolean.
FALSE;
}
if (
text.
length() == 0) {
return (
Boolean)
getEmptyValue();
}
if (
_hasTextualNull(
text)) {
return (
Boolean)
getNullValue();
}
throw
ctxt.
weirdStringException(
text,
_valueClass, "only \"true\" or \"false\" recognized");
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final boolean _parseBooleanFromNumber(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
if (
jp.
getNumberType() ==
NumberType.
LONG) {
return (
jp.
getLongValue() == 0L) ?
Boolean.
FALSE :
Boolean.
TRUE;
}
// no really good logic; let's actually resort to textual comparison
String str =
jp.
getText();
if ("0.0".
equals(
str) || "0".
equals(
str)) {
return
Boolean.
FALSE;
}
return
Boolean.
TRUE;
}
protected
Byte _parseByte(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getByteValue();
}
if (
t ==
JsonToken.
VALUE_STRING) { // let's do implicit re-parse
String text =
jp.
getText().
trim();
if (
_hasTextualNull(
text)) {
return (
Byte)
getNullValue();
}
int
value;
try {
int
len =
text.
length();
if (
len == 0) {
return (
Byte)
getEmptyValue();
}
value =
NumberInput.
parseInt(
text);
} catch (
IllegalArgumentException iae) {
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid Byte value");
}
// So far so good: but does it fit?
// as per [JACKSON-804], allow range up to 255, inclusive
if (
value <
Byte.
MIN_VALUE ||
value > 255) {
throw
ctxt.
weirdStringException(
text,
_valueClass, "overflow, value can not be represented as 8-bit value");
}
return
Byte.
valueOf((byte)
value);
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Byte)
getNullValue();
}
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected
Short _parseShort(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getShortValue();
}
if (
t ==
JsonToken.
VALUE_STRING) { // let's do implicit re-parse
String text =
jp.
getText().
trim();
int
value;
try {
int
len =
text.
length();
if (
len == 0) {
return (
Short)
getEmptyValue();
}
if (
_hasTextualNull(
text)) {
return (
Short)
getNullValue();
}
value =
NumberInput.
parseInt(
text);
} catch (
IllegalArgumentException iae) {
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid Short value");
}
// So far so good: but does it fit?
if (
value <
Short.
MIN_VALUE ||
value >
Short.
MAX_VALUE) {
throw
ctxt.
weirdStringException(
text,
_valueClass, "overflow, value can not be represented as 16-bit value");
}
return
Short.
valueOf((short)
value);
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Short)
getNullValue();
}
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final short _parseShortPrimitive(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
int
value =
_parseIntPrimitive(
jp,
ctxt);
// So far so good: but does it fit?
if (
value <
Short.
MIN_VALUE ||
value >
Short.
MAX_VALUE) {
throw
ctxt.
weirdStringException(
String.
valueOf(
value),
_valueClass, "overflow, value can not be represented as 16-bit value");
}
return (short)
value;
}
protected final int _parseIntPrimitive(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
// Int works as is, coercing fine as well
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getIntValue();
}
if (
t ==
JsonToken.
VALUE_STRING) { // let's do implicit re-parse
String text =
jp.
getText().
trim();
if (
_hasTextualNull(
text)) {
return 0;
}
try {
int
len =
text.
length();
if (
len > 9) {
long
l =
Long.
parseLong(
text);
if (
l <
Integer.
MIN_VALUE ||
l >
Integer.
MAX_VALUE) {
throw
ctxt.
weirdStringException(
text,
_valueClass,
"Overflow: numeric value ("+
text+") out of range of int ("+
Integer.
MIN_VALUE+" - "+
Integer.
MAX_VALUE+")");
}
return (int)
l;
}
if (
len == 0) {
return 0;
}
return
NumberInput.
parseInt(
text);
} catch (
IllegalArgumentException iae) {
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid int value");
}
}
if (
t ==
JsonToken.
VALUE_NULL) {
return 0;
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final
Integer _parseInteger(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
Integer.
valueOf(
jp.
getIntValue());
}
if (
t ==
JsonToken.
VALUE_STRING) { // let's do implicit re-parse
String text =
jp.
getText().
trim();
try {
int
len =
text.
length();
if (
_hasTextualNull(
text)) {
return (
Integer)
getNullValue();
}
if (
len > 9) {
long
l =
Long.
parseLong(
text);
if (
l <
Integer.
MIN_VALUE ||
l >
Integer.
MAX_VALUE) {
throw
ctxt.
weirdStringException(
text,
_valueClass,
"Overflow: numeric value ("+
text+") out of range of Integer ("+
Integer.
MIN_VALUE+" - "+
Integer.
MAX_VALUE+")");
}
return
Integer.
valueOf((int)
l);
}
if (
len == 0) {
return (
Integer)
getEmptyValue();
}
return
Integer.
valueOf(
NumberInput.
parseInt(
text));
} catch (
IllegalArgumentException iae) {
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid Integer value");
}
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Integer)
getNullValue();
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final
Long _parseLong(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
// it should be ok to coerce (although may fail, too)
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) {
return
jp.
getLongValue();
}
// let's allow Strings to be converted too
if (
t ==
JsonToken.
VALUE_STRING) {
// !!! 05-Jan-2009, tatu: Should we try to limit value space, JDK is too lenient?
String text =
jp.
getText().
trim();
if (
text.
length() == 0) {
return (
Long)
getEmptyValue();
}
if (
_hasTextualNull(
text)) {
return (
Long)
getNullValue();
}
try {
return
Long.
valueOf(
NumberInput.
parseLong(
text));
} catch (
IllegalArgumentException iae) { }
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid Long value");
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Long)
getNullValue();
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final long _parseLongPrimitive(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) {
return
jp.
getLongValue();
}
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
if (
text.
length() == 0 ||
_hasTextualNull(
text)) {
return 0L;
}
try {
return
NumberInput.
parseLong(
text);
} catch (
IllegalArgumentException iae) { }
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid long value");
}
if (
t ==
JsonToken.
VALUE_NULL) {
return 0L;
}
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final
Float _parseFloat(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
// We accept couple of different types; obvious ones first:
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getFloatValue();
}
// And finally, let's allow Strings to be converted too
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
if (
text.
length() == 0) {
return (
Float)
getEmptyValue();
}
if (
_hasTextualNull(
text)) {
return (
Float)
getNullValue();
}
switch (
text.
charAt(0)) {
case 'I':
if ("Infinity".
equals(
text) || "INF".
equals(
text)) {
return
Float.
POSITIVE_INFINITY;
}
break;
case 'N':
if ("NaN".
equals(
text)) {
return
Float.
NaN;
}
break;
case '-':
if ("-Infinity".
equals(
text) || "-INF".
equals(
text)) {
return
Float.
NEGATIVE_INFINITY;
}
break;
}
try {
return
Float.
parseFloat(
text);
} catch (
IllegalArgumentException iae) { }
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid Float value");
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Float)
getNullValue();
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final float _parseFloatPrimitive(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getFloatValue();
}
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
if (
text.
length() == 0 ||
_hasTextualNull(
text)) {
return 0.0f;
}
switch (
text.
charAt(0)) {
case 'I':
if (
_isPosInf(
text)) {
return
Float.
POSITIVE_INFINITY;
}
break;
case 'N':
if (
_isNaN(
text)) {
return
Float.
NaN;
}
break;
case '-':
if (
_isNegInf(
text)) {
return
Float.
NEGATIVE_INFINITY;
}
break;
}
try {
return
Float.
parseFloat(
text);
} catch (
IllegalArgumentException iae) { }
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid float value");
}
if (
t ==
JsonToken.
VALUE_NULL) {
return 0.0f;
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final
Double _parseDouble(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getDoubleValue();
}
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
if (
text.
length() == 0) {
return (
Double)
getEmptyValue();
}
if (
_hasTextualNull(
text)) {
return (
Double)
getNullValue();
}
switch (
text.
charAt(0)) {
case 'I':
if (
_isPosInf(
text)) {
return
Double.
POSITIVE_INFINITY;
}
break;
case 'N':
if (
_isNaN(
text)) {
return
Double.
NaN;
}
break;
case '-':
if (
_isNegInf(
text)) {
return
Double.
NEGATIVE_INFINITY;
}
break;
}
try {
return
parseDouble(
text);
} catch (
IllegalArgumentException iae) { }
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid Double value");
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (
Double)
getNullValue();
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected final double _parseDoublePrimitive(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
// We accept couple of different types; obvious ones first:
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT ||
t ==
JsonToken.
VALUE_NUMBER_FLOAT) { // coercing should work too
return
jp.
getDoubleValue();
}
// And finally, let's allow Strings to be converted too
if (
t ==
JsonToken.
VALUE_STRING) {
String text =
jp.
getText().
trim();
if (
text.
length() == 0 ||
_hasTextualNull(
text)) {
return 0.0;
}
switch (
text.
charAt(0)) {
case 'I':
if (
_isPosInf(
text)) {
return
Double.
POSITIVE_INFINITY;
}
break;
case 'N':
if (
_isNaN(
text)) {
return
Double.
NaN;
}
break;
case '-':
if (
_isNegInf(
text)) {
return
Double.
NEGATIVE_INFINITY;
}
break;
}
try {
return
parseDouble(
text);
} catch (
IllegalArgumentException iae) { }
throw
ctxt.
weirdStringException(
text,
_valueClass, "not a valid double value");
}
if (
t ==
JsonToken.
VALUE_NULL) {
return 0.0;
}
// Otherwise, no can do:
throw
ctxt.
mappingException(
_valueClass,
t);
}
protected java.util.
Date _parseDate(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
JsonToken t =
jp.
getCurrentToken();
if (
t ==
JsonToken.
VALUE_NUMBER_INT) {
return new java.util.
Date(
jp.
getLongValue());
}
if (
t ==
JsonToken.
VALUE_NULL) {
return (java.util.
Date)
getNullValue();
}
if (
t ==
JsonToken.
VALUE_STRING) {
String value = null;
try {
// As per [JACKSON-203], take empty Strings to mean
value =
jp.
getText().
trim();
if (
value.
length() == 0) {
return (
Date)
getEmptyValue();
}
if (
_hasTextualNull(
value)) {
return (java.util.
Date)
getNullValue();
}
return
ctxt.
parseDate(
value);
} catch (
IllegalArgumentException iae) {
throw
ctxt.
weirdStringException(
value,
_valueClass,
"not a valid representation (error: "+
iae.
getMessage()+")");
}
}
throw
ctxt.
mappingException(
_valueClass,
t);
}
/**
* Helper method for encapsulating calls to low-level double value parsing; single place
* just because we need a work-around that must be applied to all calls.
*/
protected final static double
parseDouble(
String numStr) throws
NumberFormatException
{
// [JACKSON-486]: avoid some nasty float representations... but should it be MIN_NORMAL or MIN_VALUE?
// for now, MIN_VALUE, since MIN_NORMAL is JDK 1.6
if (
NumberInput.
NASTY_SMALL_DOUBLE.
equals(
numStr)) {
return
Double.
MIN_VALUE;
}
return
Double.
parseDouble(
numStr);
}
/**
* Helper method used for accessing String value, if possible, doing
* necessary conversion or throwing exception as necessary.
*
* @since 2.1
*/
protected final
String _parseString(
JsonParser jp,
DeserializationContext ctxt)
throws
IOException,
JsonProcessingException
{
String value =
jp.
getValueAsString();
if (
value != null) {
return
value;
}
throw
ctxt.
mappingException(
String.class,
jp.
getCurrentToken());
}
/**
* Helper method called to determine if we are seeing String value of
* "null", and, further, that it should be coerced to null just like
* null token.
*
* @since 2.3
*/
protected boolean
_hasTextualNull(
String value) {
return "null".
equals(
value);
}
protected final boolean
_isNegInf(
String text) {
return "-Infinity".
equals(
text) || "-INF".
equals(
text);
}
protected final boolean
_isPosInf(
String text) {
return "Infinity".
equals(
text) || "INF".
equals(
text);
}
protected final boolean
_isNaN(
String text) { return "NaN".
equals(
text); }
/*
/****************************************************
/* Helper methods for sub-classes, resolving dependencies
/****************************************************
*/
/**
* Helper method used to locate deserializers for properties the
* type this deserializer handles contains (usually for properties of
* bean types)
*
* @param type Type of property to deserialize
* @param property Actual property object (field, method, constuctor parameter) used
* for passing deserialized values; provided so deserializer can be contextualized if necessary (since 1.7)
*/
protected
JsonDeserializer<
Object> findDeserializer(
DeserializationContext ctxt,
JavaType type,
BeanProperty property)
throws
JsonMappingException
{
return
ctxt.
findContextualValueDeserializer(
type,
property);
}
/*
/**********************************************************
/* Helper methods for sub-classes, deserializer construction
/**********************************************************
*/
/**
* Helper method that can be used to see if specified property has annotation
* indicating that a converter is to be used for contained values (contents
* of structured types; array/List/Map values)
*
* @param existingDeserializer (optional) configured content
* serializer if one already exists.
*
* @since 2.2
*/
protected
JsonDeserializer<?> findConvertingContentDeserializer(
DeserializationContext ctxt,
BeanProperty prop,
JsonDeserializer<?>
existingDeserializer)
throws
JsonMappingException
{
final
AnnotationIntrospector intr =
ctxt.
getAnnotationIntrospector();
if (
intr != null &&
prop != null) {
Object convDef =
intr.
findDeserializationContentConverter(
prop.
getMember());
if (
convDef != null) {
Converter<
Object,
Object>
conv =
ctxt.
converterInstance(
prop.
getMember(),
convDef);
JavaType delegateType =
conv.
getInputType(
ctxt.
getTypeFactory());
if (
existingDeserializer == null) {
existingDeserializer =
ctxt.
findContextualValueDeserializer(
delegateType,
prop);
}
return new
StdDelegatingDeserializer<
Object>(
conv,
delegateType,
existingDeserializer);
}
}
return
existingDeserializer;
}
/*
/**********************************************************
/* Helper methods for sub-classes, problem reporting
/**********************************************************
*/
/**
* Method called to deal with a property that did not map to a known
* Bean property. Method can deal with the problem as it sees fit (ignore,
* throw exception); but if it does return, it has to skip the matching
* Json content parser has.
*<p>
* NOTE: method signature was changed in version 1.5; explicit JsonParser
* <b>must</b> be passed since it may be something other than what
* context has. Prior versions did not include the first parameter.
*
* @param jp Parser that points to value of the unknown property
* @param ctxt Context for deserialization; allows access to the parser,
* error reporting functionality
* @param instanceOrClass Instance that is being populated by this
* deserializer, or if not known, Class that would be instantiated.
* If null, will assume type is what {@link #getValueClass} returns.
* @param propName Name of the property that can not be mapped
*/
protected void handleUnknownProperty(
JsonParser jp,
DeserializationContext ctxt,
Object instanceOrClass,
String propName)
throws
IOException,
JsonProcessingException
{
if (
instanceOrClass == null) {
instanceOrClass =
handledType();
}
// Maybe we have configured handler(s) to take care of it?
if (
ctxt.
handleUnknownProperty(
jp, this,
instanceOrClass,
propName)) {
return;
}
// Nope, not handled. Potentially that's a problem...
ctxt.
reportUnknownProperty(
instanceOrClass,
propName, this);
/* But if we do get this far, need to skip whatever value we
* are pointing to now.
*/
jp.
skipChildren();
}
}