这个反序列化一般都不会出问题,但是但是但是,墨菲定理,在实习中发现了一年前的代码存在有关反序列化的问题;
具体是原本场景就是直接读数据库,可通过Jackson反序列化读出来的数据,竟然和数据库中的不一样;
所以就针对Jackson反序列化的规则以及源码进行分析
如果参数不全则直接异常:
无参构造需要set/get方法来完成序列化和反序列化
下图是有无参构造且有对应的set/get方法的程序截图,可以看出,age成功读取2;
/**
* Method to deserialize JSON content from given JSON content String.
*
* @throws IOException if a low-level I/O problem (unexpected end-of-input,
* network error) occurs (passed through as-is without additional wrapping -- note
* that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
* does NOT result in wrapping of exception even if enabled)
* @throws JsonParseException if underlying input contains invalid content
* of type {@link JsonParser} supports (JSON for default case)
* @throws JsonMappingException if the input JSON structure does not match structure
* expected for result type (or has other mismatch issues)
*/
@SuppressWarnings("unchecked")
public <T> T readValue(String content, Class<T> valueType)
throws IOException, JsonParseException, JsonMappingException
{
return (T) _readMapAndClose(_jsonFactory.createParser(content), _typeFactory.constructType(valueType));
}
/**
* Method for constructing parser for parsing
* contents of given String.
*
* @since 2.1
*/
public JsonParser createParser(String content) throws IOException, JsonParseException {
final int strLen = content.length();
// Actually, let's use this for medium-sized content, up to 64kB chunk (32kb char)
if ((_inputDecorator != null) || (strLen > 0x8000) || !canUseCharArrays()) {
// easier to just wrap in a Reader than extend InputDecorator; or, if content
// is too long for us to copy it over
return createParser(new StringReader(content));
}
IOContext ctxt = _createContext(content, true);
char[] buf = ctxt.allocTokenBuffer(strLen);
content.getChars(0, strLen, buf, 0);
return _createParser(buf, 0, strLen, ctxt, true);
}
public JavaType constructType(Type type) {
return _fromAny(null, type, EMPTY_BINDINGS);
}
/**
* Factory method that can be used if type information is passed
* as Java typing returned from <code>getGenericXxx</code> methods
* (usually for a return or argument type).
*/
protected JavaType _fromAny(ClassStack context, Type type, TypeBindings bindings)
{
JavaType resultType;
// simple class?
if (type instanceof Class<?>) {
// Important: remove possible bindings since this is type-erased thingy
resultType = _fromClass(context, (Class<?>) type, EMPTY_BINDINGS);
}
// But if not, need to start resolving.
else if (type instanceof ParameterizedType) {
resultType = _fromParamType(context, (ParameterizedType) type, bindings);
}
else if (type instanceof JavaType) { // [databind#116]
// no need to modify further if we already had JavaType
return (JavaType) type;
}
else if (type instanceof GenericArrayType) {
resultType = _fromArrayType(context, (GenericArrayType) type, bindings);
}
else if (type instanceof TypeVariable<?>) {
resultType = _fromVariable(context, (TypeVariable<?>) type, bindings);
}
else if (type instanceof WildcardType) {
resultType = _fromWildcard(context, (WildcardType) type, bindings);
} else {
// sanity check
throw new IllegalArgumentException("Unrecognized Type: "+((type == null) ? "[null]" : type.toString()));
}
// 21-Feb-2016, nateB/tatu: as per [databind#1129] (applied for 2.7.2),
// we do need to let all kinds of types to be refined, esp. for Scala module.
if (_modifiers != null) {
TypeBindings b = resultType.getBindings();
if (b == null) {
b = EMPTY_BINDINGS;
}
for (TypeModifier mod : _modifiers) {
JavaType t = mod.modifyType(resultType, type, b, this);
if (t == null) {
throw new IllegalStateException(String.format(
"TypeModifier %s (of type %s) return null for type %s",
mod, mod.getClass().getName(), resultType));
}
resultType = t;
}
}
return resultType;
}
/**
* @param bindings Mapping of formal parameter declarations (for generic
* types) into actual types
*/
protected JavaType _fromClass(ClassStack context, Class<?> rawType, TypeBindings bindings)
{
// Very first thing: small set of core types we know well:
JavaType result = _findWellKnownSimple(rawType);
if (result != null) {
return result;
}
// Barring that, we may have recently constructed an instance
final Object key;
if ((bindings == null) || bindings.isEmpty()) {
key = rawType;
} else {
key = bindings.asKey(rawType);
}
result = _typeCache.get(key); // ok, cache object is synced
if (result != null) {
return result;
}
// 15-Oct-2015, tatu: recursive reference?
if (context == null) {
context = new ClassStack(rawType);
} else {
ClassStack prev = context.find(rawType);
if (prev != null) {
// Self-reference: needs special handling, then...
ResolvedRecursiveType selfRef = new ResolvedRecursiveType(rawType, EMPTY_BINDINGS);
prev.addSelfReference(selfRef);
return selfRef;
}
// no, but need to update context to allow for proper cycle resolution
context = context.child(rawType);
}
// First: do we have an array type?
if (rawType.isArray()) {
result = ArrayType.construct(_fromAny(context, rawType.getComponentType(), bindings),
bindings);
} else {
// If not, need to proceed by first resolving parent type hierarchy
JavaType superClass;
JavaType[] superInterfaces;
if (rawType.isInterface()) {
superClass = null;
superInterfaces = _resolveSuperInterfaces(context, rawType, bindings);
} else {
// Note: even Enums can implement interfaces, so cannot drop those
superClass = _resolveSuperClass(context, rawType, bindings);
superInterfaces = _resolveSuperInterfaces(context, rawType, bindings);
}
// 19-Oct-2015, tatu: Bit messy, but we need to 'fix' java.util.Properties here...
if (rawType == Properties.class) {
result = MapType.construct(rawType, bindings, superClass, superInterfaces,
CORE_TYPE_STRING, CORE_TYPE_STRING);
}
// And then check what flavor of type we got. Start by asking resolved
// super-type if refinement is all that is needed?
else if (superClass != null) {
result = superClass.refine(rawType, bindings, superClass, superInterfaces);
}
// if not, perhaps we are now resolving a well-known class or interface?
if (result == null) {
result = _fromWellKnownClass(context, rawType, bindings, superClass, superInterfaces);
if (result == null) {
result = _fromWellKnownInterface(context, rawType, bindings, superClass, superInterfaces);
if (result == null) {
// but if nothing else, "simple" class for now:
result = _newSimpleType(rawType, bindings, superClass, superInterfaces);
}
}
}
}
context.resolveSelfReferences(result);
// 16-Jul-2016, tatu: [databind#1302] is solved different way, but ideally we shouldn't
// cache anything with partially resolved `ResolvedRecursiveType`... so maybe improve
if (!result.hasHandlers()) {
_typeCache.putIfAbsent(key, result); // cache object syncs
}
return result;
}
protected Object _readMapAndClose(JsonParser p0, JavaType valueType)
throws IOException
{
try (JsonParser p = p0) {
Object result;
JsonToken t = _initForReading(p, valueType);
final DeserializationConfig cfg = getDeserializationConfig();
final DeserializationContext ctxt = createDeserializationContext(p, cfg);
if (t == JsonToken.VALUE_NULL) {
// Ask JsonDeserializer what 'null value' to use:
result = _findRootDeserializer(ctxt, valueType).getNullValue(ctxt);
} else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
result = null;
} else {
JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, valueType);
if (cfg.useRootWrapping()) {
result = _unwrapAndDeserialize(p, ctxt, cfg, valueType, deser);
} else {
result = deser.deserialize(p, ctxt);
}
ctxt.checkUnresolvedObjectId();
}
if (cfg.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
_verifyNoTrailingTokens(p, ctxt, valueType);
}
return result;
}
}
protected DefaultDeserializationContext createDeserializationContext(JsonParser p,
DeserializationConfig cfg) {
return _deserializationContext.createInstance(cfg, p, _injectableValues);
}
/**
* Method called to locate deserializer for the passed root-level value.
*/
protected JsonDeserializer<Object> _findRootDeserializer(DeserializationContext ctxt,
JavaType valueType)
throws JsonMappingException
{
// First: have we already seen it?
JsonDeserializer<Object> deser = _rootDeserializers.get(valueType);
if (deser != null) {
return deser;
}
// Nope: need to ask provider to resolve it
deser = ctxt.findRootValueDeserializer(valueType);
if (deser == null) { // can this happen?
return ctxt.reportBadDefinition(valueType,
"Cannot find a deserializer for type "+valueType);
}
_rootDeserializers.put(valueType, deser);
return deser;
}
/**
* Method for finding a deserializer for root-level value.
*/
@SuppressWarnings("unchecked")
public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
throws JsonMappingException
{
JsonDeserializer<Object> deser = _cache.findValueDeserializer(this,
_factory, type);
if (deser == null) { // can this occur?
return null;
}
deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null, type);
TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
if (typeDeser != null) {
// important: contextualize to indicate this is for root value
typeDeser = typeDeser.forProperty(null);
return new TypeWrappedDeserializer(typeDeser, deser);
}
return deser;
}
/**
* Method called to get hold of a deserializer for a value of given type;
* or if no such deserializer can be found, a default handler (which
* may do a best-effort generic serialization or just simply
* throw an exception when invoked).
*<p>
* Note: this method is only called for value types; not for keys.
* Key deserializers can be accessed using {@link #findKeyDeserializer}.
*<p>
* Note also that deserializer returned is guaranteed to be resolved
* (if it is of type {@link ResolvableDeserializer}), but
* not contextualized (wrt {@link ContextualDeserializer}): caller
* has to handle latter if necessary.
*
* @param ctxt Deserialization context
* @param propertyType Declared type of the value to deserializer (obtained using
* 'setter' method signature and/or type annotations
*
* @throws JsonMappingException if there are fatal problems with
* accessing suitable deserializer; including that of not
* finding any serializer
*/
public JsonDeserializer<Object> findValueDeserializer(DeserializationContext ctxt,
DeserializerFactory factory, JavaType propertyType)
throws JsonMappingException
{
JsonDeserializer<Object> deser = _findCachedDeserializer(propertyType);
if (deser == null) {
// If not, need to request factory to construct (or recycle)
deser = _createAndCacheValueDeserializer(ctxt, factory, propertyType);
if (deser == null) {
/* Should we let caller handle it? Let's have a helper method
* decide it; can throw an exception, or return a valid
* deserializer
*/
deser = _handleUnknownValueDeserializer(ctxt, propertyType);
}
}
return deser;
}
/**
* Method that is to actually build a bean deserializer instance.
* All basic sanity checks have been done to know that what we have
* may be a valid bean type, and that there are no default simple
* deserializers.
*/
@SuppressWarnings("unchecked")
public JsonDeserializer<Object> buildBeanDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc)
throws JsonMappingException
{
// First: check what creators we can use, if any
ValueInstantiator valueInstantiator;
/* 04-Jun-2015, tatu: To work around [databind#636], need to catch the
* issue, defer; this seems like a reasonable good place for now.
* Note, however, that for non-Bean types (Collections, Maps) this
* probably won't work and needs to be added elsewhere.
*/
try {
valueInstantiator = findValueInstantiator(ctxt, beanDesc);
} catch (NoClassDefFoundError error) {
return new ErrorThrowingDeserializer(error);
} catch (IllegalArgumentException e) {
// 05-Apr-2017, tatu: Although it might appear cleaner to require collector
// to throw proper exception, it doesn't actually have reference to this
// instance so...
throw InvalidDefinitionException.from(ctxt.getParser(),
ClassUtil.exceptionMessage(e),
beanDesc, null);
}
BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
builder.setValueInstantiator(valueInstantiator);
// And then setters for deserializing from JSON Object
addBeanProps(ctxt, beanDesc, builder);
addObjectIdReader(ctxt, beanDesc, builder);
// managed/back reference fields/setters need special handling... first part
addBackReferenceProperties(ctxt, beanDesc, builder);
addInjectables(ctxt, beanDesc, builder);
final DeserializationConfig config = ctxt.getConfig();
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
builder = mod.updateBuilder(config, beanDesc, builder);
}
}
JsonDeserializer<?> deserializer;
if (type.isAbstract() && !valueInstantiator.canInstantiate()) {
deserializer = builder.buildAbstract();
} else {
deserializer = builder.build();
}
// may have modifier(s) that wants to modify or replace serializer we just built
// (note that `resolve()` and `createContextual()` called later on)
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deserializer = mod.modifyDeserializer(config, beanDesc, deserializer);
}
}
return (JsonDeserializer<Object>) deserializer;
}
/**
* Method called to figure out settable properties for the
* bean deserializer to use.
*<p>
* Note: designed to be overridable, and effort is made to keep interface
* similar between versions.
*/
protected void addBeanProps(DeserializationContext ctxt,
BeanDescription beanDesc, BeanDeserializerBuilder builder)
throws JsonMappingException
{
final boolean isConcrete = !beanDesc.getType().isAbstract();
final SettableBeanProperty[] creatorProps = isConcrete
? builder.getValueInstantiator().getFromObjectArguments(ctxt.getConfig())
: null;
final boolean hasCreatorProps = (creatorProps != null);
// 01-May-2016, tatu: Which base type to use here gets tricky, since
// it may often make most sense to use general type for overrides,
// but what we have here may be more specific impl type. But for now
// just use it as is.
JsonIgnoreProperties.Value ignorals = ctxt.getConfig()
.getDefaultPropertyIgnorals(beanDesc.getBeanClass(),
beanDesc.getClassInfo());
Set<String> ignored;
if (ignorals != null) {
boolean ignoreAny = ignorals.getIgnoreUnknown();
builder.setIgnoreUnknownProperties(ignoreAny);
// Or explicit/implicit definitions?
ignored = ignorals.findIgnoredForDeserialization();
for (String propName : ignored) {
builder.addIgnorable(propName);
}
} else {
ignored = Collections.emptySet();
}
// Also, do we have a fallback "any" setter?
AnnotatedMember anySetter = beanDesc.findAnySetterAccessor();
if (anySetter != null) {
builder.setAnySetter(constructAnySetter(ctxt, beanDesc, anySetter));
} else {
// 23-Jan-2018, tatu: although [databind#1805] would suggest we should block
// properties regardless, for now only consider unless there's any setter...
Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames();
if (ignored2 != null) {
for (String propName : ignored2) {
// allow ignoral of similarly named JSON property, but do not force;
// latter means NOT adding this to 'ignored':
builder.addIgnorable(propName);
}
}
}
final boolean useGettersAsSetters = ctxt.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS)
&& ctxt.isEnabled(MapperFeature.AUTO_DETECT_GETTERS);
// Ok: let's then filter out property definitions
List<BeanPropertyDefinition> propDefs = filterBeanProps(ctxt,
beanDesc, builder, beanDesc.findProperties(), ignored);
// After which we can let custom code change the set
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
propDefs = mod.updateProperties(ctxt.getConfig(), beanDesc, propDefs);
}
}
// At which point we still have all kinds of properties; not all with mutators:
for (BeanPropertyDefinition propDef : propDefs) {
SettableBeanProperty prop = null;
// 18-Oct-2013, tatu: Although constructor parameters have highest precedence,
// we need to do linkage (as per [databind#318]), and so need to start with
// other types, and only then create constructor parameter, if any.
if (propDef.hasSetter()) {
AnnotatedMethod setter = propDef.getSetter();
JavaType propertyType = setter.getParameterType(0);
prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
} else if (propDef.hasField()) {
AnnotatedField field = propDef.getField();
JavaType propertyType = field.getType();
prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
} else {
// NOTE: specifically getter, since field was already checked above
AnnotatedMethod getter = propDef.getGetter();
if (getter != null) {
if (useGettersAsSetters && _isSetterlessType(getter.getRawType())) {
// 23-Jan-2018, tatu: As per [databind#1805], need to ensure we don't
// accidentally sneak in getter-as-setter for `READ_ONLY` properties
if (builder.hasIgnorable(propDef.getName())) {
;
} else {
prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
}
} else if (!propDef.hasConstructorParameter()) {
PropertyMetadata md = propDef.getMetadata();
// 25-Oct-2016, tatu: If merging enabled, might not need setter.
// We cannot quite support this with creator parameters; in theory
// possibly, but right not not due to complexities of routing, so
// just prevent
if (md.getMergeInfo() != null) {
prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
}
}
}
}
// 25-Sep-2014, tatu: No point in finding constructor parameters for abstract types
// (since they are never used anyway)
if (hasCreatorProps && propDef.hasConstructorParameter()) {
/* If property is passed via constructor parameter, we must
* handle things in special way. Not sure what is the most optimal way...
* for now, let's just call a (new) method in builder, which does nothing.
*/
// but let's call a method just to allow custom builders to be aware...
final String name = propDef.getName();
CreatorProperty cprop = null;
if (creatorProps != null) {
for (SettableBeanProperty cp : creatorProps) {
if (name.equals(cp.getName()) && (cp instanceof CreatorProperty)) {
cprop = (CreatorProperty) cp;
break;
}
}
}
if (cprop == null) {
List<String> n = new ArrayList<>();
for (SettableBeanProperty cp : creatorProps) {
n.add(cp.getName());
}
ctxt.reportBadPropertyDefinition(beanDesc, propDef,
"Could not find creator property with name '%s' (known Creator properties: %s)",
name, n);
continue;
}
if (prop != null) {
cprop.setFallbackSetter(prop);
}
Class<?>[] views = propDef.findViews();
if (views == null) {
views = beanDesc.findDefaultViews();
}
cprop.setViews(views);
builder.addCreatorProperty(cprop);
continue;
}
if (prop != null) {
// one more thing before adding to builder: copy any metadata
Class<?>[] views = propDef.findViews();
if (views == null) {
views = beanDesc.findDefaultViews();
}
prop.setViews(views);
builder.addProperty(prop);
}
}
}
/**
* Main deserialization method for bean-based objects (POJOs).
*/
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
// common case first
if (p.isExpectedStartObjectToken()) {
if (_vanillaProcessing) {
return vanillaDeserialize(p, ctxt, p.nextToken());
}
// 23-Sep-2015, tatu: This is wrong at some many levels, but for now... it is
// what it is, including "expected behavior".
p.nextToken();
if (_objectIdReader != null) {
return deserializeWithObjectId(p, ctxt);
}
return deserializeFromObject(p, ctxt);
}
return _deserializeOther(p, ctxt, p.getCurrentToken());
}
/**
* Streamlined version that is only used when no "special"
* features are enabled.
*/
private final Object vanillaDeserialize(JsonParser p,
DeserializationContext ctxt, JsonToken t)
throws IOException
{
final Object bean = _valueInstantiator.createUsingDefault(ctxt); //默认构造器初始化对象
// [databind#631]: Assign current value, to be accessible by custom serializers
p.setCurrentValue(bean);
if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
String propName = p.getCurrentName();
do {
p.nextToken();
SettableBeanProperty prop = _beanProperties.find(propName); //获取字段的设置方法
if (prop != null) { // normal case
try {
prop.deserializeAndSet(p, ctxt, bean); //调用初始化字段,调用每个properties对应的方法
} catch (Exception e) {
wrapAndThrow(e, bean, propName, ctxt);
}
continue;
}
handleUnknownVanilla(p, ctxt, bean, propName);
} while ((propName = p.nextFieldName()) != null);
}
return bean;
}
@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException
{
if (_defaultCreator == null) { // sanity-check; caller should check
return super.createUsingDefault(ctxt);
}
try {
return _defaultCreator.call();
} catch (Exception e) { // 19-Apr-2017, tatu: Let's not catch Errors, just Exceptions
return ctxt.handleInstantiationProblem(_valueClass, null, rewrapCtorProblem(ctxt, e));
}
}
@Override
public final Object call() throws Exception {
return _constructor.newInstance();
}
@Override
public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) throws IOException
{
if (_withArgsCreator == null) { // sanity-check; caller should check
return super.createFromObjectWith(ctxt, args);
}
try {
return _withArgsCreator.call(args);
} catch (Exception e) { // 19-Apr-2017, tatu: Let's not catch Errors, just Exceptions
return ctxt.handleInstantiationProblem(_valueClass, args, rewrapCtorProblem(ctxt, e));
}
}
@Override
public final Object call(Object[] args) throws Exception {
return _constructor.newInstance(args);
}
/**
* Uses the constructor represented by this {@code Constructor} object to
* create and initialize a new instance of the constructor's
* declaring class, with the specified initialization parameters.
* Individual parameters are automatically unwrapped to match
* primitive formal parameters, and both primitive and reference
* parameters are subject to method invocation conversions as necessary.
*
* <p>If the number of formal parameters required by the underlying constructor
* is 0, the supplied {@code initargs} array may be of length 0 or null.
*
* <p>If the constructor's declaring class is an inner class in a
* non-static context, the first argument to the constructor needs
* to be the enclosing instance; see section 15.9.3 of
* <cite>The Java™ Language Specification</cite>.
*
* <p>If the required access and argument checks succeed and the
* instantiation will proceed, the constructor's declaring class
* is initialized if it has not already been initialized.
*
* <p>If the constructor completes normally, returns the newly
* created and initialized instance.
*
* @param initargs array of objects to be passed as arguments to
* the constructor call; values of primitive types are wrapped in
* a wrapper object of the appropriate type (e.g. a {@code float}
* in a {@link java.lang.Float Float})
*
* @return a new object created by calling the constructor
* this object represents
*
* @exception IllegalAccessException if this {@code Constructor} object
* is enforcing Java language access control and the underlying
* constructor is inaccessible.
* @exception IllegalArgumentException if the number of actual
* and formal parameters differ; if an unwrapping
* conversion for primitive arguments fails; or if,
* after possible unwrapping, a parameter value
* cannot be converted to the corresponding formal
* parameter type by a method invocation conversion; if
* this constructor pertains to an enum type.
* @exception InstantiationException if the class that declares the
* underlying constructor represents an abstract class.
* @exception InvocationTargetException if the underlying constructor
* throws an exception.
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails.
*/
@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, clazz, modifiers);
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
@Override
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
Object instance) throws IOException
{
Object value;
if (p.hasToken(JsonToken.VALUE_NULL)) {
if (_skipNulls) {
return;
}
value = _nullProvider.getNullValue(ctxt);
} else if (_valueTypeDeserializer == null) {
value = _valueDeserializer.deserialize(p, ctxt);
// 04-May-2018, tatu: [databind#2023] Coercion from String (mostly) can give null
if (value == null) {
if (_skipNulls) {
return;
}
value = _nullProvider.getNullValue(ctxt);
}
} else {
value = _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
}
try {
_setter.invoke(instance, value);
} catch (Exception e) {
_throwAsIOE(p, e, value);
}
}
@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
return p.getIntValue();
}
return _parseInteger(p, ctxt);
}
@Override
public int getIntValue() throws IOException
{
if ((_numTypesValid & NR_INT) == 0) {
if (_numTypesValid == NR_UNKNOWN) { // not parsed at all
return _parseIntValue();
}
if ((_numTypesValid & NR_INT) == 0) { // wasn't an int natively?
convertNumberToInt(); // let's make it so, if possible
}
}
return _numberInt;
}