deser = _valueDeserializer;
if (deser == MISSING_VALUE_DESERIALIZER) {
return null;
}
return deser;
}
public TypeDeserializer getValueTypeDeserializer() { return _valueTypeDeserializer; }
/**
* @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 {@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
*/
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.
*/
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 {@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).
*/
public abstract void deserializeAndSet(JsonParser p,
DeserializationContext ctxt, Object instance) throws IOException;
/**
* 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.
*/
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.
*/
public abstract Object setAndReturn(Object instance, Object value) throws IOException;
/**
* This method is needed by some specialized bean deserializers,
* and also called by some {@link #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).
*/
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
*/
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);
}
if (_valueTypeDeserializer != null) {
// 25-Oct-2021 Added by James to support merging polymorphic property
// https://github.com/FasterXML/jackson-databind/issues/2541
// Please note we only support merging same type polymorphic property for now,
// merging different type is hard and usually doesn't make sense.
// Please note you need to configure {@link DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES} as false to
// enable this feature otherwise the unknown property exception will be thrown.
JavaType subType = ctxt.getTypeFactory().constructType(toUpdate.getClass());
JsonDeserializer subTypeValueDeserializer = ctxt.findContextualValueDeserializer(subType, this);
return subTypeValueDeserializer.deserialize(p, ctxt, toUpdate);
}
// 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.
*/
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
*/
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 {@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.
*/
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 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 getAnnotation(Class 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);
}
}
}