| package org.codehaus.jackson.map.jsontype.impl; |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| |
| import org.codehaus.jackson.*; |
| import org.codehaus.jackson.annotate.JsonTypeInfo; |
| import org.codehaus.jackson.map.BeanProperty; |
| import org.codehaus.jackson.map.DeserializationContext; |
| import org.codehaus.jackson.map.JsonDeserializer; |
| import org.codehaus.jackson.map.TypeDeserializer; |
| import org.codehaus.jackson.map.jsontype.TypeIdResolver; |
| import org.codehaus.jackson.type.JavaType; |
| |
| /** |
| * @since 1.5 |
| * @author tatus |
| */ |
| public abstract class TypeDeserializerBase extends TypeDeserializer |
| { |
| protected final TypeIdResolver _idResolver; |
| |
| protected final JavaType _baseType; |
| |
| protected final BeanProperty _property; |
| |
| /** |
| * Type to use as the default implementation, if type id is |
| * missing or can not be resolved. |
| * |
| * @since 1.9 |
| */ |
| protected final JavaType _defaultImpl; |
| |
| /** |
| * For efficient operation we will lazily build mappings from type ids |
| * to actual deserializers, once needed. |
| */ |
| protected final HashMap<String,JsonDeserializer<Object>> _deserializers; |
| |
| /** |
| * @since 1.9 |
| */ |
| protected JsonDeserializer<Object> _defaultImplDeserializer; |
| |
| /** |
| * @deprecated Since 1.9, use the constructor that takes 'defaultImpl' |
| */ |
| @Deprecated |
| protected TypeDeserializerBase(JavaType baseType, TypeIdResolver idRes, BeanProperty property) { |
| this(baseType, idRes, property, null); |
| } |
| |
| protected TypeDeserializerBase(JavaType baseType, TypeIdResolver idRes, BeanProperty property, |
| Class<?> defaultImpl) |
| { |
| _baseType = baseType; |
| _idResolver = idRes; |
| _property = property; |
| _deserializers = new HashMap<String,JsonDeserializer<Object>>(); |
| if (defaultImpl == null) { |
| _defaultImpl = null; |
| } else { |
| /* 16-Oct-2011, tatu: should call this via TypeFactory; this is |
| * not entirely safe... however, since Collections/Maps are |
| * seldom (if ever) base types, may be ok. |
| */ |
| _defaultImpl = baseType.forcedNarrowBy(defaultImpl); |
| } |
| } |
| |
| @Override |
| public abstract JsonTypeInfo.As getTypeInclusion(); |
| |
| public String baseTypeName() { return _baseType.getRawClass().getName(); } |
| |
| @Override |
| public String getPropertyName() { return null; } |
| |
| @Override |
| public TypeIdResolver getTypeIdResolver() { return _idResolver; } |
| |
| @Override |
| public Class<?> getDefaultImpl() { |
| return (_defaultImpl == null) ? null : _defaultImpl.getRawClass(); |
| } |
| |
| @Override |
| public String toString() |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.append('[').append(getClass().getName()); |
| sb.append("; base-type:").append(_baseType); |
| sb.append("; id-resolver: ").append(_idResolver); |
| sb.append(']'); |
| return sb.toString(); |
| } |
| |
| /* |
| /********************************************************** |
| /* Helper methods for sub-classes |
| /********************************************************** |
| */ |
| |
| protected final JsonDeserializer<Object> _findDeserializer(DeserializationContext ctxt, String typeId) |
| throws IOException, JsonProcessingException |
| { |
| JsonDeserializer<Object> deser; |
| |
| synchronized (_deserializers) { |
| deser = _deserializers.get(typeId); |
| if (deser == null) { |
| JavaType type = _idResolver.typeFromId(typeId); |
| if (type == null) { |
| // As per [JACKSON-614], use the default impl if no type id available: |
| if (_defaultImpl == null) { |
| throw ctxt.unknownTypeException(_baseType, typeId); |
| } |
| deser = _findDefaultImplDeserializer(ctxt); |
| } else { |
| /* 16-Dec-2010, tatu: Since nominal type we get here has no (generic) type parameters, |
| * we actually now need to explicitly narrow from base type (which may have parameterization) |
| * using raw type. |
| * |
| * One complication, though; can not change 'type class' (simple type to container); otherwise |
| * we may try to narrow a SimpleType (Object.class) into MapType (Map.class), losing actual |
| * type in process (getting SimpleType of Map.class which will not work as expected) |
| */ |
| if (_baseType != null && _baseType.getClass() == type.getClass()) { |
| type = _baseType.narrowBy(type.getRawClass()); |
| } |
| deser = ctxt.getDeserializerProvider().findValueDeserializer(ctxt.getConfig(), type, _property); |
| } |
| _deserializers.put(typeId, deser); |
| } |
| } |
| return deser; |
| } |
| |
| protected final JsonDeserializer<Object> _findDefaultImplDeserializer(DeserializationContext ctxt) |
| throws IOException, JsonProcessingException |
| { |
| if (_defaultImpl == null) { |
| return null; |
| } |
| synchronized (_defaultImpl) { |
| if (_defaultImplDeserializer == null) { |
| _defaultImplDeserializer = ctxt.getDeserializerProvider().findValueDeserializer(ctxt.getConfig(), |
| _defaultImpl, _property); |
| } |
| return _defaultImplDeserializer; |
| } |
| } |
| } |