Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.jackson.databind.deser;
  
  import java.util.HashMap;
  
  
Class that defines caching layer between callers (like com.fasterxml.jackson.databind.ObjectMapper, com.fasterxml.jackson.databind.DeserializationContext) and classes that construct deserializers (DeserializerFactory).
 
 public final class DeserializerCache
     implements java.io.Serializable // since 2.1 -- needs to be careful tho
 {
     private static final long serialVersionUID = 1L;
 
     /*
     /**********************************************************
     /* Caching
     /**********************************************************
      */

    
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.

 
         = new ConcurrentHashMap<JavaTypeJsonDeserializer<Object>>(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.
 
         = new HashMap<JavaTypeJsonDeserializer<Object>>(8);
 
     /*
     /**********************************************************
     /* Life-cycle
     /**********************************************************
      */
 
     public DeserializerCache() { }
 
     /*
     /**********************************************************
     /* JDK serialization handling
     /**********************************************************
      */
 
     Object writeReplace() {
         // instead of making this transient, just clear it:
         .clear();
         // TODO: clear out "cheap" cached deserializers?
         return this;
     }
     
     /*
     /**********************************************************
     /* Access to caching aspects
     /**********************************************************
      */

    
Method that can be used to determine how many deserializers this provider is caching currently (if it does caching: default implementation does) Exact count depends on what kind of deserializers get cached; default implementation caches only dynamically constructed deserializers, but not eagerly constructed standard deserializers (which is different from how serializer provider works).

The main use case for this method is to allow conditional flushing of deserializer cache, if certain number of entries is reached.

 
     public int cachedDeserializersCount() {
         return .size();
     }

    
Method that will drop all dynamically constructed deserializers (ones that are counted as result value for 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.
    public void flushCachedDeserializers() {
        .clear();       
    }
    /*
    /**********************************************************
    /* General deserializer locating method
    /**********************************************************
     */

    
Method called to get hold of a deserializer for a value of given type; or if no such deserializer can be found, a default handler (which may do a best-effort generic serialization or just simply throw an exception when invoked).

Note: this method is only called for value types; not for keys. Key deserializers can be accessed using findKeyDeserializer(com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.deser.DeserializerFactory,com.fasterxml.jackson.databind.JavaType).

Note also that deserializer returned is guaranteed to be resolved (if it is of type ResolvableDeserializer), but not contextualized (wrt ContextualDeserializer): caller has to handle latter if necessary.

Parameters:
ctxt Deserialization context
propertyType Declared type of the value to deserializer (obtained using 'setter' method signature and/or type annotations
Throws:
com.fasterxml.jackson.databind.JsonMappingException if there are fatal problems with accessing suitable deserializer; including that of not finding any serializer
            DeserializerFactory factoryJavaType propertyType)
        throws JsonMappingException
    {
        JsonDeserializer<Objectdeser = _findCachedDeserializer(propertyType);
        if (deser == null) {
            // If not, need to request factory to construct (or recycle)
            deser = _createAndCacheValueDeserializer(ctxtfactorypropertyType);
            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);
            }
        }
        return deser;
    }

    
Method called to get hold of a deserializer to use for deserializing keys for java.util.Map.

Throws:
com.fasterxml.jackson.databind.JsonMappingException if there are fatal problems with accessing suitable key deserializer; including that of not finding any serializer
            DeserializerFactory factoryJavaType type)
        throws JsonMappingException
    {
        KeyDeserializer kd = factory.createKeyDeserializer(ctxttype);
        if (kd == null) { // if none found, need to use a placeholder that'll fail
            return _handleUnknownKeyDeserializer(type);
        }
        // First: need to resolve?
        if (kd instanceof ResolvableDeserializer) {
            ((ResolvableDeserializerkd).resolve(ctxt);
        }
        return kd;
    }

    
Method called to find out whether provider would be able to find a deserializer for given type, using a root reference (i.e. not through fields or membership in an array or collection)
    public boolean hasValueDeserializerFor(DeserializationContext ctxt,
            DeserializerFactory factoryJavaType type)
        throws JsonMappingException
    {
        /* Note: mostly copied from findValueDeserializer, except for
         * handling of unknown types
         */
        JsonDeserializer<Objectdeser = _findCachedDeserializer(type);
        if (deser == null) {
            deser = _createAndCacheValueDeserializer(ctxtfactorytype);
        }
        return (deser != null);
    }
    /*
    /**********************************************************
    /* Helper methods that handle cache lookups
    /**********************************************************
     */
    {
        if (type == null) {
            throw new IllegalArgumentException("Null JavaType passed");
        }
        return .get(type);
    }

    
Method that will try to create a deserializer for given type, and resolve and cache it if necessary

Parameters:
ctxt Currently active deserialization context
type Type of property to deserialize
            DeserializerFactory factoryJavaType type)
        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 () {
            // Ok, then: could it be that due to a race condition, deserializer can now be found?
            JsonDeserializer<Objectdeser = _findCachedDeserializer(type);
            if (deser != null) {
                return deser;
            }
            int count = .size();
            // Or perhaps being resolved right now?
            if (count > 0) {
                deser = .get(type);
                if (deser != null) {
                    return deser;
                }
            }
            // Nope: need to create and possibly cache
            try {
                return _createAndCache2(ctxtfactorytype);
            } finally {
                // also: any deserializers that have been created are complete by now
                if (count == 0 && .size() > 0) {
                    .clear();
                }
            }
        }
    }

    
Method that handles actual construction (via factory) and caching (both intermediate and eventual)
            DeserializerFactory factoryJavaType type)
        throws JsonMappingException
    {
        JsonDeserializer<Objectdeser;
        try {
            deser = _createDeserializer(ctxtfactorytype);
        } catch (IllegalArgumentException iae) {
            /* We better only expose checked exceptions, since those
             * are what caller is expected to handle
             */
            throw new JsonMappingException(iae.getMessage(), nulliae);
        }
        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.isCachable();
        /* 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) {
            .put(typedeser);
            ((ResolvableDeserializer)deser).resolve(ctxt);
            .remove(type);
        }
        if (addToCache) {
            .put(typedeser);
        }
        return deser;
    }
    /*
    /**********************************************************
    /* Helper methods for actual construction of deserializers
    /**********************************************************
     */
    
    
Method that does the heavy lifting of checking for per-type annotations, find out full type, and figure out which actual factory method to call.
    @SuppressWarnings("unchecked")
            DeserializerFactory factoryJavaType type)
        throws JsonMappingException
    {
        final DeserializationConfig config = ctxt.getConfig();
        // First things first: do we need to use abstract type mapping?
        if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) {
            type = factory.mapAbstractType(configtype);
        }
        BeanDescription beanDesc = config.introspect(type);
        // Then: does type define explicit deserializer to use, with annotation(s)?
                beanDesc.getClassInfo());
        if (deser != null) {
            return deser;
        }
        // If not, may have further type-modification annotations to check:
        JavaType newType = modifyTypeByAnnotation(ctxtbeanDesc.getClassInfo(), type);
        if (newType != type) {
            type = newType;
            beanDesc = config.introspect(newType);
        }
        // We may also have a Builder type to consider...
        Class<?> builder = beanDesc.findPOJOBuilder();
        if (builder != null) {
            return (JsonDeserializer<Object>) factory.createBuilderBasedDeserializer(
            		ctxttypebeanDescbuilder);
        }
        // Or perhaps a Converter?
        Converter<Object,Objectconv = beanDesc.findDeserializationConverter();
        if (conv == null) { // nope, just construct in normal way
            return (JsonDeserializer<Object>) _createDeserializer2(ctxtfactorytypebeanDesc);
        }
        // otherwise need to do bit of introspection
        JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
        // One more twist, as per [Issue#288]; probably need to get new BeanDesc
        if (!delegateType.hasRawClass(type.getRawClass())) {
            beanDesc = config.introspect(delegateType);
        }
        return new StdDelegatingDeserializer<Object>(convdelegateType,
                _createDeserializer2(ctxtfactorydelegateTypebeanDesc));
    }
            DeserializerFactory factoryJavaType typeBeanDescription beanDesc)
        throws JsonMappingException
    {
        final DeserializationConfig config = ctxt.getConfig();
        // If not, let's see which factory method to use:
        if (type.isEnumType()) {
            return factory.createEnumDeserializer(ctxttypebeanDesc);
        }
        if (type.isContainerType()) {
            if (type.isArrayType()) {
                return factory.createArrayDeserializer(ctxt, (ArrayTypetypebeanDesc);
            }
            if (type.isMapLikeType()) {
                MapLikeType mlt = (MapLikeTypetype;
                if (mlt.isTrueMapType()) {
                    return factory.createMapDeserializer(ctxt,(MapTypemltbeanDesc);
                }
                return factory.createMapLikeDeserializer(ctxtmltbeanDesc);
            }
            if (type.isCollectionLikeType()) {
                /* 03-Aug-2012, tatu: As per [Issue#40], one exception is if shape
                 *   is to be Shape.OBJECT. Ideally we'd determine it bit later on
                 *   (to allow custom handler checks), but that won't work for other
                 *   reasons. So do it here.
                 */
                JsonFormat.Value format = beanDesc.findExpectedFormat(null);
                if (format == null || format.getShape() != ..) {
                    CollectionLikeType clt = (CollectionLikeTypetype;
                    if (clt.isTrueCollectionType()) {
                        return factory.createCollectionDeserializer(ctxt, (CollectionTypecltbeanDesc);
                    }
                    return factory.createCollectionLikeDeserializer(ctxtcltbeanDesc);
                }
            }
        }
        if (JsonNode.class.isAssignableFrom(type.getRawClass())) {
            return factory.createTreeDeserializer(configtypebeanDesc);
        }
        return factory.createBeanDeserializer(ctxttypebeanDesc);
    }

    
Helper method called to check if a class or method has annotation that tells which class to use for deserialization. Returns null if no such annotation found.
            Annotated ann)
        throws JsonMappingException
    {
        Object deserDef = ctxt.getAnnotationIntrospector().findDeserializer(ann);
        if (deserDef == null) {
            return null;
        }
        JsonDeserializer<Objectdeser = ctxt.deserializerInstance(anndeserDef);
        // One more thing however: may need to also apply a converter:
        return findConvertingDeserializer(ctxtanndeser);
    }

    
Helper method that will check whether given annotated entity (usually class, but may also be a property accessor) indicates that a com.fasterxml.jackson.databind.util.Converter is to be used; and if so, to construct and return suitable serializer for it. If not, will simply return given serializer as is.
            Annotated aJsonDeserializer<Objectdeser)
        throws JsonMappingException
    {
        Converter<Object,Objectconv = findConverter(ctxta);
        if (conv == null) {
            return deser;
        }
        JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
        return (JsonDeserializer<Object>) new StdDelegatingDeserializer<Object>(convdelegateTypedeser);
    }
            Annotated a)
        throws JsonMappingException
    {
        Object convDef = ctxt.getAnnotationIntrospector().findDeserializationConverter(a);
        if (convDef == null) {
            return null;
        }
        return ctxt.converterInstance(aconvDef);
    }    
    
Method called to see if given method has annotations that indicate a more specific type than what the argument specifies. If annotations are present, they must specify compatible Class; instance of which can be assigned using the method. This means that the Class has to be raw class of type, or its sub-class (or, implementing class if original Class instance is an interface).

Parameters:
a Method or field that the type is associated with
type Type derived from the setter argument
Returns:
Original type if no annotations are present; or a more specific type derived from it if type annotation(s) was found
Throws:
com.fasterxml.jackson.databind.JsonMappingException if invalid annotation is found
            Annotated aJavaType type)
        throws JsonMappingException
    {
        // first: let's check class for the instance itself:
        AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
        Class<?> subclass = intr.findDeserializationType(atype);
        if (subclass != null) {
            try {
                type = type.narrowBy(subclass);
            } catch (IllegalArgumentException iae) {
                throw new JsonMappingException("Failed to narrow type "+type+" with concrete-type annotation (value "+subclass.getName()+"), method '"+a.getName()+"': "+iae.getMessage(), nulliae);
            }
        }
        // then key class
        if (type.isContainerType()) {
            Class<?> keyClass = intr.findDeserializationKeyType(atype.getKeyType());
            if (keyClass != null) {
                // illegal to use on non-Maps
                if (!(type instanceof MapLikeType)) {
                    throw new JsonMappingException("Illegal key-type annotation: type "+type+" is not a Map(-like) type");
                }
                try {
                    type = ((MapLikeTypetype).narrowKey(keyClass);
                } catch (IllegalArgumentException iae) {
                    throw new JsonMappingException("Failed to narrow key type "+type+" with key-type annotation ("+keyClass.getName()+"): "+iae.getMessage(), nulliae);
                }
            }
            JavaType keyType = type.getKeyType();
            /* 21-Mar-2011, tatu: ... and associated deserializer too (unless already assigned)
             *   (not 100% why or how, but this does seem to get called more than once, which
             *   is not good: for now, let's just avoid errors)
             */
            if (keyType != null && keyType.getValueHandler() == null) {
                Object kdDef = intr.findKeyDeserializer(a);
                if (kdDef != null) {
                    KeyDeserializer kd = ctxt.keyDeserializerInstance(akdDef);
                    if (kd != null) {
                        type = ((MapLikeTypetype).withKeyValueHandler(kd);
                        keyType = type.getKeyType(); // just in case it's used below
                    }
                }
            }            
            
            // and finally content class; only applicable to structured types
            Class<?> cc = intr.findDeserializationContentType(atype.getContentType());
            if (cc != null) {
                try {
                    type = type.narrowContentsBy(cc);
                } catch (IllegalArgumentException iae) {
                    throw new JsonMappingException("Failed to narrow content type "+type+" with content-type annotation ("+cc.getName()+"): "+iae.getMessage(), nulliae);
                }
            }
            // ... as well as deserializer for contents:
            JavaType contentType = type.getContentType();
            if (contentType.getValueHandler() == null) { // as with above, avoid resetting (which would trigger exception)
                Object cdDef = intr.findContentDeserializer(a);
                if (cdDef != null) {
                    JsonDeserializer<?> cd = null;
                    if (cdDef instanceof JsonDeserializer<?>) {
                        cdDef = (JsonDeserializer<?>) cdDef;
                    } else {
                        Class<?> cdClass = _verifyAsClass(cdDef"findContentDeserializer"JsonDeserializer.None.class);
                        if (cdClass != null) {
                            cd = ctxt.deserializerInstance(acdClass);
                        }
                    }
                    if (cd != null) {
                        type = type.withContentValueHandler(cd);
                    }
                }
            }
        }
        return type;
    }
    private Class<?> _verifyAsClass(Object srcString methodNameClass<?> noneClass)
    {
        if (src == null) {
            return null;
        }
        if (!(src instanceof Class)) {
            throw new IllegalStateException("AnnotationIntrospector."+methodName+"() returned value of type "+src.getClass().getName()+": expected type JsonSerializer or Class<JsonSerializer> instead");
        }
        Class<?> cls = (Class<?>) src;
        if (cls == noneClass || cls == NoClass.class) {
            return null;
        }
        return cls;
    }
    
    /*
    /**********************************************************
    /* Overridable error reporting methods
    /**********************************************************
     */
        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);
    }
        throws JsonMappingException
    {
        throw new JsonMappingException("Can not find a (Map) Key deserializer for type "+type);
    }
New to GrepCode? Check out our FAQ X