package com.fasterxml.jackson.databind.deser;
import java.io.IOException;
import java.util.*;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.impl.ObjectIdReader;
import com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator;
import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.ObjectIdInfo;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
public class AbstractDeserializer
extends JsonDeserializer<Object>
implements ContextualDeserializer,
java.io.Serializable
{
private static final long serialVersionUID = 1L;
protected final JavaType _baseType;
protected final ObjectIdReader _objectIdReader;
protected final Map<String, SettableBeanProperty> _backRefProperties;
protected transient Map<String,SettableBeanProperty> _properties;
protected final boolean _acceptString;
protected final boolean _acceptBoolean;
protected final boolean _acceptInt;
protected final boolean _acceptDouble;
public AbstractDeserializer(BeanDeserializerBuilder builder,
BeanDescription beanDesc, Map<String, SettableBeanProperty> backRefProps,
Map<String, SettableBeanProperty> props)
{
_baseType = beanDesc.getType();
_objectIdReader = builder.getObjectIdReader();
_backRefProperties = backRefProps;
_properties = props;
Class<?> cls = _baseType.getRawClass();
_acceptString = cls.isAssignableFrom(String.class);
_acceptBoolean = (cls == Boolean.TYPE) || cls.isAssignableFrom(Boolean.class);
_acceptInt = (cls == Integer.TYPE) || cls.isAssignableFrom(Integer.class);
_acceptDouble = (cls == Double.TYPE) || cls.isAssignableFrom(Double.class);
}
@Deprecated
public AbstractDeserializer(BeanDeserializerBuilder builder,
BeanDescription beanDesc, Map<String, SettableBeanProperty> backRefProps) {
this(builder, beanDesc, backRefProps, null);
}
protected AbstractDeserializer(BeanDescription beanDesc)
{
_baseType = beanDesc.getType();
_objectIdReader = null;
_backRefProperties = null;
Class<?> cls = _baseType.getRawClass();
_acceptString = cls.isAssignableFrom(String.class);
_acceptBoolean = (cls == Boolean.TYPE) || cls.isAssignableFrom(Boolean.class);
_acceptInt = (cls == Integer.TYPE) || cls.isAssignableFrom(Integer.class);
_acceptDouble = (cls == Double.TYPE) || cls.isAssignableFrom(Double.class);
}
protected AbstractDeserializer(AbstractDeserializer base,
ObjectIdReader objectIdReader, Map<String, SettableBeanProperty> props)
{
_baseType = base._baseType;
_backRefProperties = base._backRefProperties;
_acceptString = base._acceptString;
_acceptBoolean = base._acceptBoolean;
_acceptInt = base._acceptInt;
_acceptDouble = base._acceptDouble;
_objectIdReader = objectIdReader;
_properties = props;
}
public static AbstractDeserializer constructForNonPOJO(BeanDescription beanDesc) {
return new AbstractDeserializer(beanDesc);
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException
{
final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (property != null && intr != null) {
final AnnotatedMember accessor = property.getMember();
if (accessor != null) {
ObjectIdInfo objectIdInfo = intr.findObjectIdInfo(accessor);
if (objectIdInfo != null) {
JavaType idType;
ObjectIdGenerator<?> idGen;
SettableBeanProperty idProp = null;
ObjectIdResolver resolver = ctxt.objectIdResolverInstance(accessor, objectIdInfo);
objectIdInfo = intr.findObjectReferenceInfo(accessor, objectIdInfo);
Class<?> implClass = objectIdInfo.getGeneratorType();
if (implClass == ObjectIdGenerators.PropertyGenerator.class) {
PropertyName propName = objectIdInfo.getPropertyName();
idProp = (_properties == null) ? null : _properties.get(propName.getSimpleName());
if (idProp == null) {
ctxt.reportBadDefinition(_baseType, String.format(
"Invalid Object Id definition for %s: cannot find property with name '%s'",
handledType().getName(), propName));
}
idType = idProp.getType();
idGen = new PropertyBasedObjectIdGenerator(objectIdInfo.getScope());
} else {
resolver = ctxt.objectIdResolverInstance(accessor, objectIdInfo);
JavaType type = ctxt.constructType(implClass);
idType = ctxt.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0];
idGen = ctxt.objectIdGeneratorInstance(accessor, objectIdInfo);
}
JsonDeserializer<?> deser = ctxt.findRootValueDeserializer(idType);
ObjectIdReader oir = ObjectIdReader.construct(idType, objectIdInfo.getPropertyName(),
idGen, deser, idProp, resolver);
return new AbstractDeserializer(this, oir, null);
}
}
}
if (_properties == null) {
return this;
}
return new AbstractDeserializer(this, _objectIdReader, null);
}
@Override
public Class<?> handledType() {
return _baseType.getRawClass();
}
@Override
public boolean isCachable() { return true; }
@Override
public Boolean supportsUpdate(DeserializationConfig config) {
return null;
}
@Override
public ObjectIdReader getObjectIdReader() {
return _objectIdReader;
}
@Override
public SettableBeanProperty findBackReference(String logicalName) {
return (_backRefProperties == null) ? null : _backRefProperties.get(logicalName);
}
@Override
public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws IOException
{
if (_objectIdReader != null) {
JsonToken t = p.getCurrentToken();
if (t != null) {
if (t.isScalarValue()) {
return _deserializeFromObjectId(p, ctxt);
}
if (t == JsonToken.START_OBJECT) {
t = p.nextToken();
}
if ((t == JsonToken.FIELD_NAME) && _objectIdReader.maySerializeAsObject()
&& _objectIdReader.isValidReferencePropertyName(p.getCurrentName(), p)) {
return _deserializeFromObjectId(p, ctxt);
}
}
}
Object result = _deserializeIfNatural(p, ctxt);
if (result != null) {
return result;
}
return typeDeserializer.deserializeTypedFromObject(p, ctxt);
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException
{
ValueInstantiator bogus = new ValueInstantiator.Base(_baseType);
return ctxt.handleMissingInstantiator(_baseType.getRawClass(), bogus, p,
"abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information");
}
protected Object _deserializeIfNatural(JsonParser p, DeserializationContext ctxt) throws IOException
{
switch (p.getCurrentTokenId()) {
case JsonTokenId.ID_STRING:
if (_acceptString) {
return p.getText();
}
break;
case JsonTokenId.ID_NUMBER_INT:
if (_acceptInt) {
return p.getIntValue();
}
break;
case JsonTokenId.ID_NUMBER_FLOAT:
if (_acceptDouble) {
return Double.valueOf(p.getDoubleValue());
}
break;
case JsonTokenId.ID_TRUE:
if (_acceptBoolean) {
return Boolean.TRUE;
}
break;
case JsonTokenId.ID_FALSE:
if (_acceptBoolean) {
return Boolean.FALSE;
}
break;
}
return null;
}
protected Object _deserializeFromObjectId(JsonParser p, DeserializationContext ctxt) throws IOException
{
Object id = _objectIdReader.readObjectReference(p, ctxt);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator, _objectIdReader.resolver);
Object pojo = roid.resolve();
if (pojo == null) {
throw new UnresolvedForwardReference(p,
"Could not resolve Object Id ["+id+"] -- unresolved forward-reference?", p.getCurrentLocation(), roid);
}
return pojo;
}
}