_keyDeserializers = StdKeyDeserializers.constructAll();
/**
* We will also cache some dynamically constructed deserializers;
* specifically, ones that are expensive to construct.
* This currently means bean and Enum deserializers; array, List and Map
* deserializers will not be cached.
*
* Given that we don't expect much concurrency for additions
* (should very quickly converge to zero after startup), let's
* explicitly define a low concurrency setting.
*/
final protected ConcurrentHashMap> _cachedDeserializers
= new ConcurrentHashMap>(64, 0.75f, 2);
/**
* During deserializer construction process we may need to keep track of partially
* completed deserializers, to resolve cyclic dependencies. This is the
* map used for storing deserializers before they are fully complete.
*/
final protected HashMap> _incompleteDeserializers
= new HashMap>(8);
/*
/**********************************************************
/* Configuration
/**********************************************************
*/
/**
* Factory responsible for constructing actual deserializers, if not
* one of pre-configured types.
*/
protected DeserializerFactory _factory;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
/**
* Default constructor. Equivalent to calling
*
* new StdDeserializerProvider(BeanDeserializerFactory.instance);
*
*/
public StdDeserializerProvider() { this(BeanDeserializerFactory.instance); }
public StdDeserializerProvider(DeserializerFactory f) {
_factory = f;
}
@Override
public DeserializerProvider withAdditionalDeserializers(Deserializers d) {
_factory = _factory.withAdditionalDeserializers(d);
return this;
}
@Override
public DeserializerProvider withAdditionalKeyDeserializers(KeyDeserializers d) {
_factory = _factory.withAdditionalKeyDeserializers(d);
return this;
}
@Override
public DeserializerProvider withDeserializerModifier(BeanDeserializerModifier modifier) {
_factory = _factory.withDeserializerModifier(modifier);
return this;
}
@Override
public DeserializerProvider withAbstractTypeResolver(AbstractTypeResolver resolver) {
_factory = _factory.withAbstractTypeResolver(resolver);
return this;
}
/*
/**********************************************************
/* Abstract methods impls
/**********************************************************
*/
@SuppressWarnings("unchecked")
@Override
public JsonDeserializer findValueDeserializer(DeserializationConfig config,
JavaType propertyType, BeanProperty property)
throws JsonMappingException
{
JsonDeserializer deser = _findCachedDeserializer(propertyType);
if (deser != null) {
// [JACKSON-385]: need to support contextualization:
if (deser instanceof ContextualDeserializer>) {
JsonDeserializer> d = ((ContextualDeserializer>) deser).createContextual(config, property);
deser = (JsonDeserializer) d;
}
return deser;
}
// If not, need to request factory to construct (or recycle)
deser = _createAndCacheValueDeserializer(config, propertyType, property);
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(propertyType);
}
// [JACKSON-385]: need to support contextualization:
if (deser instanceof ContextualDeserializer>) {
JsonDeserializer> d = ((ContextualDeserializer>) deser).createContextual(config, property);
deser = (JsonDeserializer) d;
}
return deser;
}
@Override
public JsonDeserializer findTypedValueDeserializer(DeserializationConfig config,
JavaType type, BeanProperty property)
throws JsonMappingException
{
JsonDeserializer deser = findValueDeserializer(config, type, property);
TypeDeserializer typeDeser = _factory.findTypeDeserializer(config, type, property);
if (typeDeser != null) {
return new WrappedDeserializer(typeDeser, deser);
}
return deser;
}
@Override
public KeyDeserializer findKeyDeserializer(DeserializationConfig config,
JavaType type, BeanProperty property)
throws JsonMappingException
{
// 1.8: check if there are custom key deserializers...
KeyDeserializer kd = _factory.createKeyDeserializer(config, type, property);
if (kd == null) {
// No serializer needed if it's plain old String, or Object/untyped
Class> raw = type.getRawClass();
if (raw == String.class || raw == Object.class) {
return null;
}
// Most other keys are of limited number of static types
KeyDeserializer kdes = _keyDeserializers.get(type);
if (kdes != null) {
return kdes;
}
// And then other one-offs; first, Enum:
if (type.isEnumType()) {
return StdKeyDeserializers.constructEnumKeyDeserializer(config, type);
}
// One more thing: can we find ctor(String) or valueOf(String)?
kdes = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type);
if (kdes != null) {
return kdes;
}
if (kd == null) {
// otherwise, will probably fail:
return _handleUnknownKeyDeserializer(type);
}
}
// One more thing: contextuality:
if (kd instanceof ContextualKeyDeserializer) {
kd = ((ContextualKeyDeserializer) kd).createContextual(config, property);
}
return kd;
}
/**
* Method that can be called to find out whether a deserializer can
* be found for given type
*/
@Override
public boolean hasValueDeserializerFor(DeserializationConfig config, JavaType type)
{
/* Note: mostly copied from findValueDeserializer, except for
* handling of unknown types
*/
JsonDeserializer deser = _findCachedDeserializer(type);
if (deser == null) {
try {
deser = _createAndCacheValueDeserializer(config, type, null);
} catch (Exception e) {
return false;
}
}
return (deser != null);
}
@Override
public int cachedDeserializersCount() {
return _cachedDeserializers.size();
}
/**
* Method that will drop all dynamically constructed deserializers (ones that
* are counted as result value for {@link #cachedDeserializersCount}).
* This can be used to remove memory usage (in case some deserializers are
* only used once or so), or to force re-construction of deserializers after
* configuration changes for mapper than owns the provider.
*
* @since 1.4
*/
@Override
public void flushCachedDeserializers() {
_cachedDeserializers.clear();
}
/*
/**********************************************************
/* Overridable helper methods
/**********************************************************
*/
protected JsonDeserializer _findCachedDeserializer(JavaType type)
{
return _cachedDeserializers.get(type);
}
/**
* Method that will try to create a deserializer for given type,
* and resolve and cache it if necessary
*
* @param config Configuration
* @param type Type of property to deserializer
* @param property Property (field, setter, ctor arg) to use deserializer for
*/
protected JsonDeserializer_createAndCacheValueDeserializer(DeserializationConfig config,
JavaType type, BeanProperty property)
throws JsonMappingException
{
/* Only one thread to construct deserializers at any given point in time;
* limitations necessary to ensure that only completely initialized ones
* are visible and used.
*/
synchronized (_incompleteDeserializers) {
// Ok, then: could it be that due to a race condition, deserializer can now be found?
JsonDeserializer deser = _findCachedDeserializer(type);
if (deser != null) {
return deser;
}
int count = _incompleteDeserializers.size();
// Or perhaps being resolved right now?
if (count > 0) {
deser = _incompleteDeserializers.get(type);
if (deser != null) {
return deser;
}
}
// Nope: need to create and possibly cache
try {
return _createAndCache2(config, type, property);
} finally {
// also: any deserializers that have been created are complete by now
if (count == 0 && _incompleteDeserializers.size() > 0) {
_incompleteDeserializers.clear();
}
}
}
}
/**
* Method that handles actual construction (via factory) and caching (both
* intermediate and eventual)
*/
protected JsonDeserializer _createAndCache2(DeserializationConfig config, JavaType type,
BeanProperty property)
throws JsonMappingException
{
JsonDeserializer deser;
try {
deser = _createDeserializer(config, type, property);
} catch (IllegalArgumentException iae) {
/* We better only expose checked exceptions, since those
* are what caller is expected to handle
*/
throw new JsonMappingException(iae.getMessage(), null, iae);
}
if (deser == null) {
return null;
}
/* cache resulting deserializer? always true for "plain" BeanDeserializer
* (but can be re-defined for sub-classes by using @JsonCachable!)
*/
// 08-Jun-2010, tatu: Related to [JACKSON-296], need to avoid caching MapSerializers... so:
boolean isResolvable = (deser instanceof ResolvableDeserializer);
boolean addToCache = (deser.getClass() == BeanDeserializer.class);
if (!addToCache) {
// 14-Feb-2011, tatu: As per [JACKSON-487], try fully blocking annotation access:
if (config.isEnabled(DeserializationConfig.Feature.USE_ANNOTATIONS)) {
AnnotationIntrospector aintr = config.getAnnotationIntrospector();
// note: pass 'null' to prevent mix-ins from being used
AnnotatedClass ac = AnnotatedClass.construct(deser.getClass(), aintr, null);
Boolean cacheAnn = aintr.findCachability(ac);
if (cacheAnn != null) {
addToCache = cacheAnn.booleanValue();
}
}
}
/* we will temporarily hold on to all created deserializers (to
* handle cyclic references, and possibly reuse non-cached
* deserializers (list, map))
*/
/* 07-Jun-2010, tatu: Danger: [JACKSON-296] was caused by accidental
* resolution of a reference -- couple of ways to prevent this;
* either not add Lists or Maps, or clear references eagerly.
* Let's actually do both; since both seem reasonable.
*/
/* Need to resolve? Mostly done for bean deserializers; required for
* resolving cyclic references.
*/
if (isResolvable) {
_incompleteDeserializers.put(type, deser);
_resolveDeserializer(config, (ResolvableDeserializer)deser);
_incompleteDeserializers.remove(type);
}
if (addToCache) {
_cachedDeserializers.put(type, deser);
}
return deser;
}
/* Refactored so we can isolate the casts that require suppression
* of type-safety warnings.
*/
@SuppressWarnings("unchecked")
protected JsonDeserializer _createDeserializer(DeserializationConfig config,
JavaType type, BeanProperty property)
throws JsonMappingException
{
if (type.isEnumType()) {
return (JsonDeserializer) _factory.createEnumDeserializer(config, this, type, property);
}
if (type.isContainerType()) {
if (type.isArrayType()) {
return (JsonDeserializer)_factory.createArrayDeserializer(config, this,
(ArrayType) type, property);
}
if (type.isMapLikeType()) {
MapLikeType mlt = (MapLikeType) type;
if (mlt.isTrueMapType()) {
return (JsonDeserializer)_factory.createMapDeserializer(config, this,
(MapType) mlt, property);
}
return (JsonDeserializer)_factory.createMapLikeDeserializer(config, this,
mlt, property);
}
if (type.isCollectionLikeType()) {
CollectionLikeType clt = (CollectionLikeType) type;
if (clt.isTrueCollectionType()) {
return (JsonDeserializer)_factory.createCollectionDeserializer(config, this,
(CollectionType) clt, property);
}
return (JsonDeserializer)_factory.createCollectionLikeDeserializer(config, this,
clt, property);
}
}
// 02-Mar-2009, tatu: Let's consider JsonNode to be a type of its own
if (JsonNode.class.isAssignableFrom(type.getRawClass())) {
return (JsonDeserializer)_factory.createTreeDeserializer(config, this, type, property);
}
return (JsonDeserializer)_factory.createBeanDeserializer(config, this, type, property);
}
protected void _resolveDeserializer(DeserializationConfig config, ResolvableDeserializer ser)
throws JsonMappingException
{
ser.resolve(config, this);
}
/*
/**********************************************************
/* Overridable error reporting methods
/**********************************************************
*/
protected JsonDeserializer _handleUnknownValueDeserializer(JavaType type)
throws JsonMappingException
{
/* Let's try to figure out the reason, to give better error
* messages
*/
Class> rawClass = type.getRawClass();
if (!ClassUtil.isConcrete(rawClass)) {
throw new JsonMappingException("Can not find a Value deserializer for abstract type "+type);
}
throw new JsonMappingException("Can not find a Value deserializer for type "+type);
}
protected KeyDeserializer _handleUnknownKeyDeserializer(JavaType type)
throws JsonMappingException
{
throw new JsonMappingException("Can not find a (Map) Key deserializer for type "+type);
}
/*
/**********************************************************
/* Helper classes
/**********************************************************
*/
/**
* Simple deserializer that will call configured type deserializer, passing
* in configured data deserializer, and exposing it all as a simple
* deserializer.
*/
protected final static class WrappedDeserializer
extends JsonDeserializer
{
final TypeDeserializer _typeDeserializer;
final JsonDeserializer _deserializer;
public WrappedDeserializer(TypeDeserializer typeDeser, JsonDeserializer deser)
{
super();
_typeDeserializer = typeDeser;
_deserializer = deser;
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
return _deserializer.deserializeWithType(jp, ctxt, _typeDeserializer);
}
@Override
public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws IOException, JsonProcessingException
{
// should never happen? (if it can, could call on that object)
throw new IllegalStateException("Type-wrapped deserializer's deserializeWithType should never get called");
}
}
}