/**
   * Method called to locate regular serializer, matching type serializer, and if both found, wrap
   * them in a serializer that calls both in correct sequence. This method is currently only used
   * for root-level serializer handling to allow for simpler caching. A call can always be replaced
   * by equivalent calls to access serializer and type serializer separately.
   *
   * @param valueType Declared type of value being serialized (which may not be actual runtime
   *     type); used for finding both value serializer and type serializer to use for adding
   *     polymorphic type (if any)
   * @param cache Whether resulting value serializer should be cached or not; this is just a hint
   * @param property When creating secondary serializers, property for which serializer is needed:
   *     annotations of the property (or bean that contains it) may be checked to create contextual
   *     serializers.
   */
  public JsonSerializer<Object> findTypedValueSerializer(
      JavaType valueType, boolean cache, BeanProperty property) throws JsonMappingException {
    // Two-phase lookups; local non-shared cache, then shared:
    JsonSerializer<Object> ser = _knownSerializers.typedValueSerializer(valueType);
    if (ser != null) {
      return ser;
    }
    // If not, maybe shared map already has it?
    ser = _serializerCache.typedValueSerializer(valueType);
    if (ser != null) {
      return ser;
    }

    // Well, let's just compose from pieces:
    ser = findValueSerializer(valueType, property);
    TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, valueType);
    if (typeSer != null) {
      typeSer = typeSer.forProperty(property);
      ser = new TypeWrappedSerializer(typeSer, ser);
    }
    if (cache) {
      _serializerCache.addTypedSerializer(valueType, ser);
    }
    return ser;
  }
 /**
  * Method called to get hold of a serializer for a value of given type; or if no such serializer
  * can be found, a default handler (which may do a best-effort generic serialization or just
  * simply throw an exception when invoked).
  *
  * <p>Note: this method is only called for non-null values; not for keys or null values. For
  * these, check out other accessor methods.
  *
  * <p>Note that serializers produced should NOT handle polymorphic serialization aspects; separate
  * {@link TypeSerializer} is to be constructed by caller if and as necessary.
  *
  * @throws JsonMappingException if there are fatal problems with accessing suitable serializer;
  *     including that of not finding any serializer
  */
 @SuppressWarnings("unchecked")
 public JsonSerializer<Object> findValueSerializer(Class<?> valueType, BeanProperty property)
     throws JsonMappingException {
   // Fast lookup from local lookup thingy works?
   JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
   if (ser == null) {
     // If not, maybe shared map already has it?
     ser = _serializerCache.untypedValueSerializer(valueType);
     if (ser == null) {
       // ... possibly as fully typed?
       ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
       if (ser == null) {
         // If neither, must create
         ser = _createAndCacheUntypedSerializer(valueType);
         // Not found? Must use the unknown type serializer, which will report error later on
         if (ser == null) {
           ser = getUnknownTypeSerializer(valueType);
           // Should this be added to lookups?
           if (CACHE_UNKNOWN_MAPPINGS) {
             _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
           }
           return ser;
         }
       }
     }
   }
   // at this point, resolution has occured, but not contextualization
   return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
 }
 /**
  * Method variant used when we do NOT want contextualization to happen; it will need to be handled
  * at a later point, but caller wants to be able to do that as needed; sometimes to avoid infinite
  * loops
  *
  * @since 2.5
  */
 public JsonSerializer<Object> findValueSerializer(JavaType valueType)
     throws JsonMappingException {
   // (see comments from above method)
   JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
   if (ser == null) {
     ser = _serializerCache.untypedValueSerializer(valueType);
     if (ser == null) {
       ser = _createAndCacheUntypedSerializer(valueType);
       if (ser == null) {
         ser = getUnknownTypeSerializer(valueType.getRawClass());
         if (CACHE_UNKNOWN_MAPPINGS) {
           _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
         }
       }
     }
   }
   return ser;
 }
 /**
  * Similar to {@link #findValueSerializer(JavaType, BeanProperty)}, but used when finding
  * "primary" property value serializer (one directly handling value of the property). Difference
  * has to do with contextual resolution, and method(s) called: this method should only be called
  * when caller is certain that this is the primary property value serializer.
  *
  * @param property Property that is being handled; will never be null, and its type has to match
  *     <code>valueType</code> parameter.
  * @since 2.3
  */
 @SuppressWarnings("unchecked")
 public JsonSerializer<Object> findPrimaryPropertySerializer(
     JavaType valueType, BeanProperty property) throws JsonMappingException {
   JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
   if (ser == null) {
     ser = _serializerCache.untypedValueSerializer(valueType);
     if (ser == null) {
       ser = _createAndCacheUntypedSerializer(valueType);
       if (ser == null) {
         ser = getUnknownTypeSerializer(valueType.getRawClass());
         // Should this be added to lookups?
         if (CACHE_UNKNOWN_MAPPINGS) {
           _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
         }
         return ser;
       }
     }
   }
   return (JsonSerializer<Object>) handlePrimaryContextualization(ser, property);
 }
 /**
  * Similar to {@link #findValueSerializer(Class,BeanProperty)}, but takes full generics-aware type
  * instead of raw class. This is necessary for accurate handling of external type information, to
  * handle polymorphic types.
  *
  * @param property When creating secondary serializers, property for which serializer is needed:
  *     annotations of the property (or bean that contains it) may be checked to create contextual
  *     serializers.
  */
 @SuppressWarnings("unchecked")
 public JsonSerializer<Object> findValueSerializer(JavaType valueType, BeanProperty property)
     throws JsonMappingException {
   // (see comments from above method)
   JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
   if (ser == null) {
     ser = _serializerCache.untypedValueSerializer(valueType);
     if (ser == null) {
       ser = _createAndCacheUntypedSerializer(valueType);
       if (ser == null) {
         ser = getUnknownTypeSerializer(valueType.getRawClass());
         if (CACHE_UNKNOWN_MAPPINGS) {
           _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
         }
         return ser;
       }
     }
   }
   return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
 }
 /** @since 2.3 */
 @SuppressWarnings("unchecked")
 public JsonSerializer<Object> findPrimaryPropertySerializer(
     Class<?> valueType, BeanProperty property) throws JsonMappingException {
   JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(valueType);
   if (ser == null) {
     ser = _serializerCache.untypedValueSerializer(valueType);
     if (ser == null) {
       ser = _serializerCache.untypedValueSerializer(_config.constructType(valueType));
       if (ser == null) {
         ser = _createAndCacheUntypedSerializer(valueType);
         if (ser == null) {
           ser = getUnknownTypeSerializer(valueType);
           if (CACHE_UNKNOWN_MAPPINGS) {
             _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
           }
           return ser;
         }
       }
     }
   }
   return (JsonSerializer<Object>) handlePrimaryContextualization(ser, property);
 }
  protected JsonSerializer<Object> _createAndCacheUntypedSerializer(JavaType type)
      throws JsonMappingException {
    JsonSerializer<Object> ser;
    try {
      ser = _createUntypedSerializer(type);
    } catch (IllegalArgumentException iae) {
      /* We better only expose checked exceptions, since those
       * are what caller is expected to handle
       */
      throw JsonMappingException.from(this, iae.getMessage(), iae);
    }

    if (ser != null) {
      _serializerCache.addAndResolveNonTypedSerializer(type, ser, this);
    }
    return ser;
  }
  /**
   * Method that will try to construct a value serializer; and if one is successfully created, cache
   * it for reuse.
   */
  protected JsonSerializer<Object> _createAndCacheUntypedSerializer(Class<?> rawType)
      throws JsonMappingException {
    JavaType fullType = _config.constructType(rawType);
    JsonSerializer<Object> ser;
    try {
      ser = _createUntypedSerializer(fullType);
    } catch (IllegalArgumentException iae) {
      /* We better only expose checked exceptions, since those
       * are what caller is expected to handle
       */
      throw JsonMappingException.from(this, iae.getMessage(), iae);
    }

    if (ser != null) {
      // 21-Dec-2015, tatu: Best to cache for both raw and full-type key
      _serializerCache.addAndResolveNonTypedSerializer(rawType, fullType, ser, this);
    }
    return ser;
  }
 /**
  * Method that will try to find a serializer, either from cache or by constructing one; but will
  * not return an "unknown" serializer if this can not be done but rather returns null.
  *
  * @return Serializer if one can be found, null if not.
  */
 protected JsonSerializer<Object> _findExplicitUntypedSerializer(Class<?> runtimeType)
     throws JsonMappingException {
   // Fast lookup from local lookup thingy works?
   JsonSerializer<Object> ser = _knownSerializers.untypedValueSerializer(runtimeType);
   if (ser == null) {
     // If not, maybe shared map already has it?
     ser = _serializerCache.untypedValueSerializer(runtimeType);
     if (ser == null) {
       ser = _createAndCacheUntypedSerializer(runtimeType);
     }
   }
   /* 18-Sep-2014, tatu: This is unfortunate patch over related change
    *    that pushes creation of "unknown type" serializer deeper down
    *    in BeanSerializerFactory; as a result, we need to "undo" creation
    *    here.
    */
   if (isUnknownTypeSerializer(ser)) {
     return null;
   }
   return ser;
 }
  /**
   * "Copy-constructor", used by sub-classes when creating actual non-blueprint instances to use.
   *
   * @param src Blueprint object used as the baseline for this instance
   */
  protected SerializerProvider(
      SerializerProvider src, SerializationConfig config, SerializerFactory f) {
    if (config == null) {
      throw new NullPointerException();
    }
    _serializerFactory = f;
    _config = config;

    _serializerCache = src._serializerCache;
    _unknownTypeSerializer = src._unknownTypeSerializer;
    _keySerializer = src._keySerializer;
    _nullValueSerializer = src._nullValueSerializer;
    _nullKeySerializer = src._nullKeySerializer;

    _stdNullValueSerializer = (_nullValueSerializer == DEFAULT_NULL_KEY_SERIALIZER);

    _serializationView = config.getActiveView();
    _attributes = config.getAttributes();

    /* Non-blueprint instances do have a read-only map; one that doesn't
     * need synchronization for lookups.
     */
    _knownSerializers = _serializerCache.getReadOnlyLookupMap();
  }