package com.fasterxml.jackson.databind.deser;

import java.io.IOException;
import java.lang.annotation.Annotation;

import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.impl.FailingDeserializer;
import com.fasterxml.jackson.databind.deser.impl.NullsConstantProvider;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.util.Annotations;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.ViewMatcher;

Base class for deserializable properties of a bean: contains both type and name definitions, and reflection-based set functionality. Concrete sub-classes implement details, so that field- and setter-backed properties, as well as a few more esoteric variations, can be handled.
/** * Base class for deserializable properties of a bean: contains * both type and name definitions, and reflection-based set functionality. * Concrete sub-classes implement details, so that field- and * setter-backed properties, as well as a few more esoteric variations, * can be handled. */
@SuppressWarnings("serial") public abstract class SettableBeanProperty extends ConcreteBeanPropertyBase implements java.io.Serializable {
To avoid nasty NPEs, let's use a placeholder for _valueDeserializer, if real deserializer is not (yet) available.
Since:2.2
/** * To avoid nasty NPEs, let's use a placeholder for _valueDeserializer, * if real deserializer is not (yet) available. * * @since 2.2 */
protected static final JsonDeserializer<Object> MISSING_VALUE_DESERIALIZER = new FailingDeserializer( "No _valueDeserializer assigned");
Logical name of the property (often but not always derived from the setter method name)
/** * Logical name of the property (often but not always derived * from the setter method name) */
protected final PropertyName _propName;
Base type for property; may be a supertype of actual value.
/** * Base type for property; may be a supertype of actual value. */
protected final JavaType _type;
Since:2.2
/** * @since 2.2 */
protected final PropertyName _wrapperName;
Class that contains this property (either class that declares the property or one of its subclasses), class that is deserialized using deserializer that contains this property.
/** * Class that contains this property (either class that declares * the property or one of its subclasses), class that is * deserialized using deserializer that contains this property. */
protected final transient Annotations _contextAnnotations;
Deserializer used for handling property value.

NOTE: has been immutable since 2.3

/** * Deserializer used for handling property value. *<p> * NOTE: has been immutable since 2.3 */
protected final JsonDeserializer<Object> _valueDeserializer;
If value will contain type information (to support polymorphic handling), this is the type deserializer used to handle type resolution.
/** * If value will contain type information (to support * polymorphic handling), this is the type deserializer * used to handle type resolution. */
protected final TypeDeserializer _valueTypeDeserializer;
Entity used for possible translation from `null` into non-null value of type of this property. Often same as _valueDeserializer, but not always.
Since:2.9
/** * Entity used for possible translation from `null` into non-null * value of type of this property. * Often same as <code>_valueDeserializer</code>, but not always. * * @since 2.9 */
protected final NullValueProvider _nullProvider; /* /********************************************************** /* Configuration that is not yet immutable; generally assigned /* during initialization process but cannot be passed to /* constructor. /********************************************************** */
If property represents a managed (forward) reference, we will need the name of reference for later linking.

TODO: should try to make immutable.

/** * If property represents a managed (forward) reference, we will need * the name of reference for later linking. *<p> * TODO: should try to make immutable. */
protected String _managedReferenceName;
This is the information for object identity associated with the property.

TODO: should try to make immutable.

/** * This is the information for object identity associated with the property. * <p> * TODO: should try to make immutable. */
protected ObjectIdInfo _objectIdInfo;
Helper object used for checking whether this property is to be included in the active view, if property is view-specific; null otherwise.

TODO: should try to make immutable.

/** * Helper object used for checking whether this property is to * be included in the active view, if property is view-specific; * null otherwise. *<p> * TODO: should try to make immutable. */
protected ViewMatcher _viewMatcher;
Index of property (within all property of a bean); assigned when all properties have been collected. Order of entries is arbitrary, but once indexes are assigned they are not changed.

TODO: should try to make immutable if at all possible

/** * Index of property (within all property of a bean); assigned * when all properties have been collected. Order of entries * is arbitrary, but once indexes are assigned they are not * changed. *<p> * TODO: should try to make immutable if at all possible */
protected int _propertyIndex = -1; /* /********************************************************** /* Life-cycle (construct & configure) /********************************************************** */ protected SettableBeanProperty(BeanPropertyDefinition propDef, JavaType type, TypeDeserializer typeDeser, Annotations contextAnnotations) { this(propDef.getFullName(), type, propDef.getWrapperName(), typeDeser, contextAnnotations, propDef.getMetadata()); } protected SettableBeanProperty(PropertyName propName, JavaType type, PropertyName wrapper, TypeDeserializer typeDeser, Annotations contextAnnotations, PropertyMetadata metadata) { super(metadata); // 09-Jan-2009, tatu: Intern()ing makes sense since Jackson parsed // field names are (usually) interned too, hence lookups will be faster. // 23-Oct-2009, tatu: should this be disabled wrt [JACKSON-180]? // Probably need not, given that namespace of field/method names // is not unbounded, unlike potential JSON names. if (propName == null) { _propName = PropertyName.NO_NAME; } else { _propName = propName.internSimpleName(); } _type = type; _wrapperName = wrapper; _contextAnnotations = contextAnnotations; _viewMatcher = null; // 30-Jan-2012, tatu: Important: contextualize TypeDeserializer now... if (typeDeser != null) { typeDeser = typeDeser.forProperty(this); } _valueTypeDeserializer = typeDeser; _valueDeserializer = MISSING_VALUE_DESERIALIZER; _nullProvider = MISSING_VALUE_DESERIALIZER; }
Constructor only used by ObjectIdValueProperty.
Since:2.3
/** * Constructor only used by {@link com.fasterxml.jackson.databind.deser.impl.ObjectIdValueProperty}. * * @since 2.3 */
protected SettableBeanProperty(PropertyName propName, JavaType type, PropertyMetadata metadata, JsonDeserializer<Object> valueDeser) { super(metadata); // as with above ctor, intern()ing probably fine if (propName == null) { _propName = PropertyName.NO_NAME; } else { _propName = propName.internSimpleName(); } _type = type; _wrapperName = null; _contextAnnotations = null; _viewMatcher = null; _valueTypeDeserializer = null; _valueDeserializer = valueDeser; // 29-Jan-2017, tatu: Presumed to be irrelevant for ObjectId values... _nullProvider = valueDeser; }
Basic copy-constructor for sub-classes to use.
/** * Basic copy-constructor for sub-classes to use. */
protected SettableBeanProperty(SettableBeanProperty src) { super(src); _propName = src._propName; _type = src._type; _wrapperName = src._wrapperName; _contextAnnotations = src._contextAnnotations; _valueDeserializer = src._valueDeserializer; _valueTypeDeserializer = src._valueTypeDeserializer; _managedReferenceName = src._managedReferenceName; _propertyIndex = src._propertyIndex; _viewMatcher = src._viewMatcher; _nullProvider = src._nullProvider; }
Copy-with-deserializer-change constructor for sub-classes to use.
/** * Copy-with-deserializer-change constructor for sub-classes to use. */
@SuppressWarnings("unchecked") protected SettableBeanProperty(SettableBeanProperty src, JsonDeserializer<?> deser, NullValueProvider nuller) { super(src); _propName = src._propName; _type = src._type; _wrapperName = src._wrapperName; _contextAnnotations = src._contextAnnotations; _valueTypeDeserializer = src._valueTypeDeserializer; _managedReferenceName = src._managedReferenceName; _propertyIndex = src._propertyIndex; if (deser == null) { _valueDeserializer = MISSING_VALUE_DESERIALIZER; } else { _valueDeserializer = (JsonDeserializer<Object>) deser; } _viewMatcher = src._viewMatcher; // 29-Jan-2017, tatu: Bit messy, but for now has to do... if (nuller == MISSING_VALUE_DESERIALIZER) { nuller = _valueDeserializer; } _nullProvider = nuller; }
Copy-with-deserializer-change constructor for sub-classes to use.
/** * Copy-with-deserializer-change constructor for sub-classes to use. */
protected SettableBeanProperty(SettableBeanProperty src, PropertyName newName) { super(src); _propName = newName; _type = src._type; _wrapperName = src._wrapperName; _contextAnnotations = src._contextAnnotations; _valueDeserializer = src._valueDeserializer; _valueTypeDeserializer = src._valueTypeDeserializer; _managedReferenceName = src._managedReferenceName; _propertyIndex = src._propertyIndex; _viewMatcher = src._viewMatcher; _nullProvider = src._nullProvider; }
Fluent factory method for constructing and returning a new instance with specified value deserializer. Note that this method should NOT change configuration of this instance.
Params:
  • deser – Deserializer to assign to the new property instance
Returns:Newly constructed instance, if value deserializer differs from the one used for this instance; or 'this' if not.
/** * Fluent factory method for constructing and returning a new instance * with specified value deserializer. * Note that this method should NOT change configuration of this instance. * * @param deser Deserializer to assign to the new property instance * * @return Newly constructed instance, if value deserializer differs from the * one used for this instance; or 'this' if not. */
public abstract SettableBeanProperty withValueDeserializer(JsonDeserializer<?> deser);
Fluent factory method for constructing and returning a new instance with specified property name. Note that this method should NOT change configuration of this instance.
Params:
  • newName – Name to use for the new instance.
Returns:Newly constructed instance, if property name differs from the one used for this instance; or 'this' if not.
/** * Fluent factory method for constructing and returning a new instance * with specified property name. * Note that this method should NOT change configuration of this instance. * * @param newName Name to use for the new instance. * * @return Newly constructed instance, if property name differs from the * one used for this instance; or 'this' if not. */
public abstract SettableBeanProperty withName(PropertyName newName);
Since:2.3
/** * @since 2.3 */
public SettableBeanProperty withSimpleName(String simpleName) { PropertyName n = (_propName == null) ? new PropertyName(simpleName) : _propName.withSimpleName(simpleName); return (n == _propName) ? this : withName(n); }
Since:2.9
/** * @since 2.9 */
public abstract SettableBeanProperty withNullProvider(NullValueProvider nva); public void setManagedReferenceName(String n) { _managedReferenceName = n; } public void setObjectIdInfo(ObjectIdInfo objectIdInfo) { _objectIdInfo = objectIdInfo; } public void setViews(Class<?>[] views) { if (views == null) { _viewMatcher = null; } else { _viewMatcher = ViewMatcher.construct(views); } }
Method used to assign index for property.
/** * Method used to assign index for property. */
public void assignIndex(int index) { if (_propertyIndex != -1) { throw new IllegalStateException("Property '"+getName()+"' already had index ("+_propertyIndex+"), trying to assign "+index); } _propertyIndex = index; }
Method called to ensure that the mutator has proper access rights to be called, as per configuration. Overridden by implementations that have mutators that require access, fields and setters.
Since:2.8.3
/** * Method called to ensure that the mutator has proper access rights to * be called, as per configuration. Overridden by implementations that * have mutators that require access, fields and setters. * * @since 2.8.3 */
public void fixAccess(DeserializationConfig config) { ; }
Since:2.9.4
/** * @since 2.9.4 */
public void markAsIgnorable() { }
Since:2.9.4
/** * @since 2.9.4 */
public boolean isIgnorable() { return false; } /* /********************************************************** /* BeanProperty impl /********************************************************** */ @Override public final String getName() { return _propName.getSimpleName(); } @Override public PropertyName getFullName() { return _propName; } @Override public JavaType getType() { return _type; } @Override public PropertyName getWrapperName() { return _wrapperName; } @Override public abstract AnnotatedMember getMember(); @Override public abstract <A extends Annotation> A getAnnotation(Class<A> acls); @Override public <A extends Annotation> A getContextAnnotation(Class<A> acls) { return _contextAnnotations.get(acls); } @Override public void depositSchemaProperty(JsonObjectFormatVisitor objectVisitor, SerializerProvider provider) throws JsonMappingException { if (isRequired()) { objectVisitor.property(this); } else { objectVisitor.optionalProperty(this); } } /* /********************************************************** /* Accessors /********************************************************** */ protected Class<?> getDeclaringClass() { return getMember().getDeclaringClass(); } public String getManagedReferenceName() { return _managedReferenceName; } public ObjectIdInfo getObjectIdInfo() { return _objectIdInfo; } public boolean hasValueDeserializer() { return (_valueDeserializer != null) && (_valueDeserializer != MISSING_VALUE_DESERIALIZER); } public boolean hasValueTypeDeserializer() { return (_valueTypeDeserializer != null); } public JsonDeserializer<Object> getValueDeserializer() { JsonDeserializer<Object> deser = _valueDeserializer; if (deser == MISSING_VALUE_DESERIALIZER) { return null; } return deser; } public TypeDeserializer getValueTypeDeserializer() { return _valueTypeDeserializer; }
Since:2.9
/** * @since 2.9 */
public NullValueProvider getNullValueProvider() { return _nullProvider; } public boolean visibleInView(Class<?> activeView) { return (_viewMatcher == null) || _viewMatcher.isVisibleForView(activeView); } public boolean hasViews() { return _viewMatcher != null; }
Method for accessing unique index of this property; indexes are assigned once all properties of a BeanDeserializer have been collected.
Returns:Index of this property
/** * Method for accessing unique index of this property; indexes are * assigned once all properties of a {@link BeanDeserializer} have * been collected. * * @return Index of this property */
public int getPropertyIndex() { return _propertyIndex; }
Method for accessing index of the creator property: for other types of properties will simply return -1.
Since:2.1
/** * Method for accessing index of the creator property: for other * types of properties will simply return -1. * * @since 2.1 */
public int getCreatorIndex() { // changed from 'return -1' in 2.7.9 / 2.8.7 throw new IllegalStateException(String.format( "Internal error: no creator index for property '%s' (of type %s)", this.getName(), getClass().getName())); }
Accessor for id of injectable value, if this bean property supports value injection.
/** * Accessor for id of injectable value, if this bean property supports * value injection. */
public Object getInjectableValueId() { return null; }
Accessor for checking whether this property is injectable, and if so, ONLY injectable (will not bind from input). Currently (2.11) can only return true for Creator-backed properties.
Returns:True if (and only if) property has injector that is also defined NOT to bind from input.
Since:2.11
/** * Accessor for checking whether this property is injectable, and if so, * ONLY injectable (will not bind from input). * Currently (2.11) can only return {@code true} for Creator-backed properties. * * @return True if (and only if) property has injector that is also defined NOT * to bind from input. * * @since 2.11 */
public boolean isInjectionOnly() { return false; } // overridden by CreatorProperty /* /********************************************************** /* Public API /********************************************************** */
Method called to deserialize appropriate value, given parser (and context), and set it using appropriate mechanism. Pre-condition is that passed parser must point to the first token that should be consumed to produce the value (the only value for scalars, multiple for Objects and Arrays).
/** * Method called to deserialize appropriate value, given parser (and * context), and set it using appropriate mechanism. * Pre-condition is that passed parser must point to the first token * that should be consumed to produce the value (the only value for * scalars, multiple for Objects and Arrays). */
public abstract void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException;
Alternative to deserializeAndSet that returns either return value of setter method called (if one is), or null to indicate that no return value is available. Mostly used to support Builder style deserialization.
Since:2.0
/** * Alternative to {@link #deserializeAndSet} that returns * either return value of setter method called (if one is), * or null to indicate that no return value is available. * Mostly used to support Builder style deserialization. * * @since 2.0 */
public abstract Object deserializeSetAndReturn(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException;
Method called to assign given value to this property, on specified Object.

Note: this is an optional operation, not supported by all implementations, creator-backed properties for example do not support this method.

/** * Method called to assign given value to this property, on * specified Object. *<p> * Note: this is an optional operation, not supported by all * implementations, creator-backed properties for example do not * support this method. */
public abstract void set(Object instance, Object value) throws IOException;
Method called to assign given value to this property, on specified Object, and return whatever delegating accessor returned (if anything)

Note: this is an optional operation, not supported by all implementations, creator-backed properties for example do not support this method.

/** * Method called to assign given value to this property, on * specified Object, and return whatever delegating accessor * returned (if anything) *<p> * Note: this is an optional operation, not supported by all * implementations, creator-backed properties for example do not * support this method. */
public abstract Object setAndReturn(Object instance, Object value) throws IOException;
This method is needed by some specialized bean deserializers, and also called by some deserializeAndSet implementations.

Pre-condition is that passed parser must point to the first token that should be consumed to produce the value (the only value for scalars, multiple for Objects and Arrays).

Note that this method is final for performance reasons: to override functionality you must override other methods that call this method; this method should also not be called directly unless you really know what you are doing (and probably not even then).

/** * This method is needed by some specialized bean deserializers, * and also called by some {@link #deserializeAndSet} implementations. *<p> * Pre-condition is that passed parser must point to the first token * that should be consumed to produce the value (the only value for * scalars, multiple for Objects and Arrays). *<p> * Note that this method is final for performance reasons: to override * functionality you must override other methods that call this method; * this method should also not be called directly unless you really know * what you are doing (and probably not even then). */
public final Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { if (p.hasToken(JsonToken.VALUE_NULL)) { return _nullProvider.getNullValue(ctxt); } if (_valueTypeDeserializer != null) { return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer); } // 04-May-2018, tatu: [databind#2023] Coercion from String (mostly) can give null Object value = _valueDeserializer.deserialize(p, ctxt); if (value == null) { value = _nullProvider.getNullValue(ctxt); } return value; }
Since:2.9
/** * @since 2.9 */
public final Object deserializeWith(JsonParser p, DeserializationContext ctxt, Object toUpdate) throws IOException { // 20-Oct-2016, tatu: Not 100% sure what to do; probably best to simply return // null value and let caller decide what to do. if (p.hasToken(JsonToken.VALUE_NULL)) { // ... except for "skip nulls" case which should just do that: if (NullsConstantProvider.isSkipper(_nullProvider)) { return toUpdate; } return _nullProvider.getNullValue(ctxt); } // 20-Oct-2016, tatu: Also tricky -- for now, report an error if (_valueTypeDeserializer != null) { ctxt.reportBadDefinition(getType(), String.format("Cannot merge polymorphic property '%s'", getName())); // return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer); } // 04-May-2018, tatu: [databind#2023] Coercion from String (mostly) can give null Object value = _valueDeserializer.deserialize(p, ctxt, toUpdate); if (value == null) { if (NullsConstantProvider.isSkipper(_nullProvider)) { return toUpdate; } value = _nullProvider.getNullValue(ctxt); } return value; } /* /********************************************************** /* Helper methods /********************************************************** */
Method that takes in exception of any type, and casts or wraps it to an IOException or its subclass.
/** * Method that takes in exception of any type, and casts or wraps it * to an IOException or its subclass. */
protected void _throwAsIOE(JsonParser p, Exception e, Object value) throws IOException { if (e instanceof IllegalArgumentException) { String actType = ClassUtil.classNameOf(value); StringBuilder msg = new StringBuilder("Problem deserializing property '") .append(getName()) .append("' (expected type: ") .append(getType()) .append("; actual type: ") .append(actType).append(")"); String origMsg = ClassUtil.exceptionMessage(e); if (origMsg != null) { msg.append(", problem: ") .append(origMsg); } else { msg.append(" (no error message provided)"); } throw JsonMappingException.from(p, msg.toString(), e); } _throwAsIOE(p, e); }
Since:2.7
/** * @since 2.7 */
protected IOException _throwAsIOE(JsonParser p, Exception e) throws IOException { ClassUtil.throwIfIOE(e); ClassUtil.throwIfRTE(e); // let's wrap the innermost problem Throwable th = ClassUtil.getRootCause(e); throw JsonMappingException.from(p, ClassUtil.exceptionMessage(th), th); } @Deprecated // since 2.7 protected IOException _throwAsIOE(Exception e) throws IOException { return _throwAsIOE((JsonParser) null, e); } // 10-Oct-2015, tatu: _Should_ be deprecated, too, but its remaining // callers cannot actually provide a JsonParser protected void _throwAsIOE(Exception e, Object value) throws IOException { _throwAsIOE((JsonParser) null, e, value); } @Override public String toString() { return "[property '"+getName()+"']"; } /* /********************************************************** /* Helper classes /********************************************************** */
Helper class that is designed to both make it easier to sub-class delegating subtypes and to reduce likelihood of breakage when new methods are added.

Class was specifically added to help with Afterburner module, but its use is not limited to only support it.

Since:2.9
/** * Helper class that is designed to both make it easier to sub-class * delegating subtypes and to reduce likelihood of breakage when * new methods are added. *<p> * Class was specifically added to help with {@code Afterburner} * module, but its use is not limited to only support it. * * @since 2.9 */
public static abstract class Delegating extends SettableBeanProperty { protected final SettableBeanProperty delegate; protected Delegating(SettableBeanProperty d) { super(d); delegate = d; }
Method sub-classes must implement, to construct a new instance with given delegate.
/** * Method sub-classes must implement, to construct a new instance * with given delegate. */
protected abstract SettableBeanProperty withDelegate(SettableBeanProperty d); protected SettableBeanProperty _with(SettableBeanProperty newDelegate) { if (newDelegate == delegate) { return this; } return withDelegate(newDelegate); } @Override public SettableBeanProperty withValueDeserializer(JsonDeserializer<?> deser) { return _with(delegate.withValueDeserializer(deser)); } @Override public SettableBeanProperty withName(PropertyName newName) { return _with(delegate.withName(newName)); } @Override public SettableBeanProperty withNullProvider(NullValueProvider nva) { return _with(delegate.withNullProvider(nva)); } @Override public void assignIndex(int index) { delegate.assignIndex(index); } @Override public void fixAccess(DeserializationConfig config) { delegate.fixAccess(config); } /* /********************************************************** /* Accessors /********************************************************** */ @Override protected Class<?> getDeclaringClass() { return delegate.getDeclaringClass(); } @Override public String getManagedReferenceName() { return delegate.getManagedReferenceName(); } @Override public ObjectIdInfo getObjectIdInfo() { return delegate.getObjectIdInfo(); } @Override public boolean hasValueDeserializer() { return delegate.hasValueDeserializer(); } @Override public boolean hasValueTypeDeserializer() { return delegate.hasValueTypeDeserializer(); } @Override public JsonDeserializer<Object> getValueDeserializer() { return delegate.getValueDeserializer(); } @Override public TypeDeserializer getValueTypeDeserializer() { return delegate.getValueTypeDeserializer(); } @Override public boolean visibleInView(Class<?> activeView) { return delegate.visibleInView(activeView); } @Override public boolean hasViews() { return delegate.hasViews(); } @Override public int getPropertyIndex() { return delegate.getPropertyIndex(); } @Override public int getCreatorIndex() { return delegate.getCreatorIndex(); } @Override public Object getInjectableValueId() { return delegate.getInjectableValueId(); } @Override public boolean isInjectionOnly() { return delegate.isInjectionOnly(); } @Override public AnnotatedMember getMember() { return delegate.getMember(); } @Override public <A extends Annotation> A getAnnotation(Class<A> acls) { return delegate.getAnnotation(acls); } /* /********************************************************** /* Extended API /********************************************************** */ public SettableBeanProperty getDelegate() { return delegate; } /* /********************************************************** /* Actual mutators /********************************************************** */ @Override public void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException { delegate.deserializeAndSet(p, ctxt, instance); } @Override public Object deserializeSetAndReturn(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException { return delegate.deserializeSetAndReturn(p, ctxt, instance); } @Override public void set(Object instance, Object value) throws IOException { delegate.set(instance, value); } @Override public Object setAndReturn(Object instance, Object value) throws IOException { return delegate.setAndReturn(instance, value); } } }