public void Serialize(JsonWriter jsonWriter, object value, Type objectType)
        {
            if (jsonWriter == null)
                throw new ArgumentNullException("jsonWriter");

            _rootContract = (objectType != null) ? Serializer._contractResolver.ResolveContract(objectType) : null;
            _rootLevel = _serializeStack.Count + 1;

            JsonContract contract = GetContractSafe(value);

            try
            {
                SerializeValue(jsonWriter, value, contract, null, null, null);
            }
            catch (Exception ex)
            {
                if (IsErrorHandled(null, contract, null, null, jsonWriter.Path, ex))
                {
                    HandleError(jsonWriter, 0);
                }
                else
                {
                    // clear context in case serializer is being used inside a converter
                    // if the converter wraps the error then not clearing the context will cause this error:
                    // "Current error context error is different to requested error."
                    ClearErrorContext();
                    throw;
                }
            }
            finally
            {
                // clear root contract to ensure that if level was > 1 then it won't
                // accidently be used for non root values
                _rootContract = null;
            }
        }
		private object CreateValueInternal (JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
		{
			if (contract != null && contract.ContractType == JsonContractType.Linq)
				return CreateJToken(reader, contract);

			do {
				switch (reader.TokenType) {
				// populate a typed object or generic dictionary/array
				// depending upon whether an objectType was supplied
				case JsonToken.StartObject:
					return CreateObject(reader, objectType, contract, member, containerContract, containerMember, existingValue);
				case JsonToken.StartArray:
					return CreateList(reader, objectType, contract, member, existingValue, null);
				case JsonToken.Integer:
				case JsonToken.Float:
				case JsonToken.Boolean:
				case JsonToken.Date:
				case JsonToken.Bytes:
					return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
				case JsonToken.String:
					string s = (string)reader.Value;

                        // convert empty string to null automatically for nullable types
					if (string.IsNullOrEmpty(s) && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable)
						return null;

                        // string that needs to be returned as a byte array should be base 64 decoded
					if (objectType == typeof(byte[]))
						return Convert.FromBase64String(s);

					return EnsureType(reader, s, CultureInfo.InvariantCulture, contract, objectType);
				case JsonToken.StartConstructor:
					string constructorName = reader.Value.ToString();

					return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType);
				case JsonToken.Null:
				case JsonToken.Undefined:
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
					if (objectType == typeof(DBNull))
						return DBNull.Value;
#endif

					return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
				case JsonToken.Raw:
					return new JRaw((string)reader.Value);
				case JsonToken.Comment:
                        // ignore
					break;
				default:
					throw JsonSerializationException.Create(reader, "Unexpected token while deserializing object: " + reader.TokenType);
				}
			} while (reader.Read());

			throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
		}
        private bool? ResolveIsReference(JsonContract contract, JsonProperty property, JsonContainerContract collectionContract, JsonProperty containerProperty)
        {
            bool? isReference = null;

            // value could be coming from a dictionary or array and not have a property
            if (property != null)
                isReference = property.IsReference;

            if (isReference == null && containerProperty != null)
                isReference = containerProperty.ItemIsReference;

            if (isReference == null && collectionContract != null)
                isReference = collectionContract.ItemIsReference;

            if (isReference == null)
                isReference = contract.IsReference;

            return isReference;
        }
		private bool CalculatePropertyDetails (JsonProperty property, ref JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target, out bool useExistingValue, out object currentValue, out JsonContract propertyContract, out bool gottenCurrentValue)
		{
			currentValue = null;
			useExistingValue = false;
			propertyContract = null;
			gottenCurrentValue = false;

			if (property.Ignored)
				return true;

			JsonToken tokenType = reader.TokenType;

			if (property.PropertyContract == null)
				property.PropertyContract = GetContractSafe(property.PropertyType);

			ObjectCreationHandling objectCreationHandling =
				property.ObjectCreationHandling.GetValueOrDefault(Serializer._objectCreationHandling);

			if ((objectCreationHandling != ObjectCreationHandling.Replace)
			             && (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject)
			             && property.Readable) {
				currentValue = property.ValueProvider.GetValue(target);
				gottenCurrentValue = true;

				if (currentValue != null) {
					propertyContract = GetContractSafe(currentValue.GetType());

					useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType());
				}
			}

			if (!property.Writable && !useExistingValue)
				return true;

			// test tokentype here because null might not be convertable to some types, e.g. ignoring null when applied to DateTime
			if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && tokenType == JsonToken.Null)
				return true;

			// test tokentype here because default value might not be convertable to actual type, e.g. default of "" for DateTime
			if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore)
			             && !HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate)
			             && JsonReader.IsPrimitiveToken(tokenType)
			             && MiscellaneousUtils.ValueEquals(reader.Value, property.GetResolvedDefaultValue()))
				return true;

			if (currentValue == null) {
				propertyContract = property.PropertyContract;
			}
			else {
				propertyContract = GetContractSafe(currentValue.GetType());

				if (propertyContract != property.PropertyContract)
					propertyConverter = GetConverter(propertyContract, property.MemberConverter, containerContract, containerProperty);
			}

			return false;
		}
		private bool HasNoDefinedType (JsonContract contract)
		{
			return (contract == null || contract.UnderlyingType == typeof(object) || contract.ContractType == JsonContractType.Linq);
		}
		private JsonArrayContract EnsureArrayContract (JsonReader reader, Type objectType, JsonContract contract)
		{
			if (contract == null)
				throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));

			JsonArrayContract arrayContract = contract as JsonArrayContract;
			if (arrayContract == null) {
				string message = @"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type '{0}' because the type requires a {1} to deserialize correctly." + Environment.NewLine +
				                             @"To fix this error either change the JSON to a {1} or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array." + Environment.NewLine;
				message = message.FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract));

				throw JsonSerializationException.Create(reader, message);
			}

			return arrayContract;
		}
		private bool ReadMetadataProperties (JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
		{
			id = null;
			newValue = null;

			if (reader.TokenType == JsonToken.PropertyName) {
				string propertyName = reader.Value.ToString();

				if (propertyName.Length > 0 && propertyName[0] == '$') {
					// read metadata properties
					// $type, $id, $ref, etc
					bool metadataProperty;

					do {
						propertyName = reader.Value.ToString();

						if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal)) {
							CheckedRead(reader);
							if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null)
								throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));

							string reference = (reader.Value != null) ? reader.Value.ToString() : null;

							CheckedRead(reader);

							if (reference != null) {
								if (reader.TokenType == JsonToken.PropertyName)
									throw JsonSerializationException.Create(reader, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));

								newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference);

								if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
									TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);

								return true;
							}
							else {
								metadataProperty = true;
							}
						}
						else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal)) {
							CheckedRead(reader);
							string qualifiedTypeName = reader.Value.ToString();

							ResolveTypeName(reader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName);

							CheckedRead(reader);

							metadataProperty = true;
						}
						else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) {
							CheckedRead(reader);

							id = (reader.Value != null) ? reader.Value.ToString() : null;

							CheckedRead(reader);
							metadataProperty = true;
						}
						else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) {
							CheckedRead(reader);
							object list = CreateList(reader, objectType, contract, member, existingValue, id);
							CheckedRead(reader);
							newValue = list;
							return true;
						}
						else {
							metadataProperty = false;
						}
					} while (metadataProperty && reader.TokenType == JsonToken.PropertyName);
				}
			}
			return false;
		}
		private object CreateObject (JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
		{
			string id;
			Type resolvedObjectType = objectType;

			if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.Ignore) {
				// don't look for metadata properties
				CheckedRead(reader);
				id = null;
			}
			else if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.ReadAhead) {
				var tokenReader = reader as JTokenReader;
				if (tokenReader == null) {
					JToken t = JToken.ReadFrom(reader);
					tokenReader = (JTokenReader)t.CreateReader();
					tokenReader.Culture = reader.Culture;
					tokenReader.DateFormatString = reader.DateFormatString;
					tokenReader.DateParseHandling = reader.DateParseHandling;
					tokenReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
					tokenReader.FloatParseHandling = reader.FloatParseHandling;
					tokenReader.SupportMultipleContent = reader.SupportMultipleContent;

					// start
					CheckedRead(tokenReader);

					reader = tokenReader;
				}

				object newValue;
				if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
					return newValue;
			}
			else {
				CheckedRead(reader);
				object newValue;
				if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
					return newValue;
			}

			if (HasNoDefinedType(contract))
				return CreateJObject(reader);

			switch (contract.ContractType) {
			case JsonContractType.Object:
				{
					bool createdFromNonDefaultCreator = false;
					JsonObjectContract objectContract = (JsonObjectContract)contract;
					object targetObject;
					// check that if type name handling is being used that the existing value is compatible with the specified type
					if (existingValue != null && (resolvedObjectType == objectType || resolvedObjectType.IsAssignableFrom(existingValue.GetType())))
						targetObject = existingValue;
					else
						targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultCreator);

					// don't populate if read from non-default creator because the object has already been read
					if (createdFromNonDefaultCreator)
						return targetObject;

					return PopulateObject(targetObject, reader, objectContract, member, id);
				}
			case JsonContractType.Primitive:
				{
					JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;
					// if the content is inside $value then read past it
					if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore
					                   && reader.TokenType == JsonToken.PropertyName
					                   && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) {
						CheckedRead(reader);

						// the token should not be an object because the $type value could have been included in the object
						// without needing the $value property
						if (reader.TokenType == JsonToken.StartObject)
							throw JsonSerializationException.Create(reader, "Unexpected token when deserializing primitive value: " + reader.TokenType);

						object value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue);

						CheckedRead(reader);
						return value;
					}
					break;
				}
			case JsonContractType.Dictionary:
				{
					JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)contract;
					object targetDictionary;

					if (existingValue == null) {
						bool createdFromNonDefaultCreator;
						IDictionary dictionary = CreateNewDictionary(reader, dictionaryContract, out createdFromNonDefaultCreator);

						if (createdFromNonDefaultCreator) {
							if (id != null)
								throw JsonSerializationException.Create(reader, "Cannot preserve reference to readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

							if (contract.OnSerializingCallbacks.Count > 0)
								throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

							if (contract.OnErrorCallbacks.Count > 0)
								throw JsonSerializationException.Create(reader, "Cannot call OnError on readonly list, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

							if (!dictionaryContract.HasParametrizedCreator)
								throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size dictionary: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
						}

						PopulateDictionary(dictionary, reader, dictionaryContract, member, id);

						if (createdFromNonDefaultCreator) {
							return dictionaryContract.ParametrizedCreator(dictionary);
						}
						else if (dictionary is IWrappedDictionary) {
							return ((IWrappedDictionary)dictionary).UnderlyingDictionary;
						}

						targetDictionary = dictionary;
					}
					else {
						targetDictionary = PopulateDictionary(dictionaryContract.ShouldCreateWrapper ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary)existingValue, reader, dictionaryContract, member, id);
					}

					return targetDictionary;
				}
			case JsonContractType.Serializable:
				{
					var serializableContract = contract as JsonISerializableContract;
					return CreateISerializable(reader, serializableContract, member, id);
				}
			}

			string message = @"Cannot deserialize the current JSON object (e.g. {{""name"":""value""}}) into type '{0}' because the type requires a {1} to deserialize correctly." + Environment.NewLine +
			                          @"To fix this error either change the JSON to a {1} or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object." + Environment.NewLine;
			message = message.FormatWith(CultureInfo.InvariantCulture, resolvedObjectType, GetExpectedDescription(contract));

			throw JsonSerializationException.Create(reader, message);
		}
        private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract collectionContract, JsonProperty containerProperty)
        {
            if (ShouldWriteReference(value, null, contract, collectionContract, containerProperty))
            {
                WriteReference(writer, value);
            }
            else
            {
                if (!CheckForCircularReference(writer, value, null, contract, collectionContract, containerProperty))
                    return;

                _serializeStack.Add(value);

                if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
                    TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Started serializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, value.GetType(), converter.GetType())), null);

                converter.WriteJson(writer, value, GetInternalSerializer());

                if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
                    TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Finished serializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, value.GetType(), converter.GetType())), null);

                _serializeStack.RemoveAt(_serializeStack.Count - 1);
            }
        }
        private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
        {
            writer.WriteStartObject();

            bool isReference = ResolveIsReference(contract, member, collectionContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Objects);
            if (isReference)
            {
                WriteReferenceIdProperty(writer, contract.UnderlyingType, value);
            }
            if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionContract, containerProperty))
            {
                WriteTypeProperty(writer, contract.UnderlyingType);
            }
        }
        private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, out JsonContract memberContract, out object memberValue)
        {
            if (!property.Ignored && property.Readable && ShouldSerialize(writer, property, value) && IsSpecified(writer, property, value))
            {
                if (property.PropertyContract == null)
                    property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType);

                memberValue = property.ValueProvider.GetValue(value);
                memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue);

                if (ShouldWriteProperty(memberValue, property))
                {
                    if (ShouldWriteReference(memberValue, property, memberContract, contract, member))
                    {
                        property.WritePropertyName(writer);
                        WriteReference(writer, memberValue);
                        return false;
                    }

                    if (!CheckForCircularReference(writer, memberValue, property, memberContract, contract, member))
                        return false;

                    if (memberValue == null)
                    {
                        JsonObjectContract objectContract = contract as JsonObjectContract;
                        Required resolvedRequired = property._required ?? ((objectContract != null) ? objectContract.ItemRequired : null) ?? Required.Default;
                        if (resolvedRequired == Required.Always)
                            throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null);
                    }

                    return true;
                }
            }

            memberContract = null;
            memberValue = null;
            return false;
        }
        private void OnSerialized(JsonWriter writer, JsonContract contract, object value)
        {
            if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
                TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Finished serializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);

            contract.InvokeOnSerialized(value, Serializer._context);
        }
        private bool CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
        {
            if (value == null || contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String)
                return true;

            ReferenceLoopHandling? referenceLoopHandling = null;

            if (property != null)
                referenceLoopHandling = property.ReferenceLoopHandling;

            if (referenceLoopHandling == null && containerProperty != null)
                referenceLoopHandling = containerProperty.ItemReferenceLoopHandling;

            if (referenceLoopHandling == null && containerContract != null)
                referenceLoopHandling = containerContract.ItemReferenceLoopHandling;

            if (_serializeStack.IndexOf(value) != -1)
            {
                string message = "Self referencing loop detected";
                if (property != null)
                    message += " for property '{0}'".FormatWith(CultureInfo.InvariantCulture, property.PropertyName);
                message += " with type '{0}'.".FormatWith(CultureInfo.InvariantCulture, value.GetType());

                switch (referenceLoopHandling.GetValueOrDefault(Serializer._referenceLoopHandling))
                {
                    case ReferenceLoopHandling.Error:
                        throw JsonSerializationException.Create(null, writer.ContainerPath, message, null);
                    case ReferenceLoopHandling.Ignore:
                        if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
                            TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, writer.Path, message + ". Skipping serializing self referenced value."), null);

                        return false;
                    case ReferenceLoopHandling.Serialize:
                        if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
                            TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, writer.Path, message + ". Serializing self referenced value."), null);

                        return true;
                }
            }

            return true;
        }
        private bool ShouldWriteReference(object value, JsonProperty property, JsonContract valueContract, JsonContainerContract collectionContract, JsonProperty containerProperty)
        {
            if (value == null)
                return false;
            if (valueContract.ContractType == JsonContractType.Primitive || valueContract.ContractType == JsonContractType.String)
                return false;

            bool? isReference = ResolveIsReference(valueContract, property, collectionContract, containerProperty);

            if (isReference == null)
            {
                if (valueContract.ContractType == JsonContractType.Array)
                    isReference = HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays);
                else
                    isReference = HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Objects);
            }

            if (!isReference.Value)
                return false;

            return Serializer.GetReferenceResolver().IsReferenced(this, value);
        }
		internal string GetExpectedDescription (JsonContract contract)
		{
			switch (contract.ContractType) {
			case JsonContractType.Object:
			case JsonContractType.Dictionary:
#if !(NETFX_CORE || PORTABLE || PORTABLE40)
			case JsonContractType.Serializable:
#endif
#if !(NET35 || NET20 || PORTABLE40)
			case JsonContractType.Dynamic:
#endif
				return @"JSON object (e.g. {""name"":""value""})";
			case JsonContractType.Array:
				return @"JSON array (e.g. [1,2,3])";
			case JsonContractType.Primitive:
				return @"JSON primitive value (e.g. string, number, boolean, null)";
			case JsonContractType.String:
				return @"JSON string value";
			default:
				throw new ArgumentOutOfRangeException();
			}
		}
		private JsonConverter GetConverter (JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty)
		{
			JsonConverter converter = null;
			if (memberConverter != null) {
				// member attribute converter
				converter = memberConverter;
			}
			else if (containerProperty != null && containerProperty.ItemConverter != null) {
				converter = containerProperty.ItemConverter;
			}
			else if (containerContract != null && containerContract.ItemConverter != null) {
				converter = containerContract.ItemConverter;
			}
			else if (contract != null) {
				JsonConverter matchingConverter;
				if (contract.Converter != null)
                    // class attribute converter
                    converter = contract.Converter;
				else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
                    // passed in converters
                    converter = matchingConverter;
				else if (contract.InternalConverter != null)
                    // internally specified converter
                    converter = contract.InternalConverter;
			}
			return converter;
		}
        private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
        {
            TypeNameHandling resolvedTypeNameHandling =
                ((member != null) ? member.TypeNameHandling : null)
                ?? ((containerProperty != null) ? containerProperty.ItemTypeNameHandling : null)
                ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
                ?? Serializer._typeNameHandling;

            if (HasFlag(resolvedTypeNameHandling, typeNameHandlingFlag))
                return true;

            // instance type and the property's type's contract default type are different (no need to put the type in JSON because the type will be created by default)
            if (HasFlag(resolvedTypeNameHandling, TypeNameHandling.Auto))
            {
                if (member != null)
                {
                    if (contract.UnderlyingType != member.PropertyContract.CreatedType)
                        return true;
                }
                else if (containerContract != null)
                {
                    if (containerContract.ItemContract == null || contract.UnderlyingType != containerContract.ItemContract.CreatedType)
                        return true;
                }
                else if (_rootContract != null && _serializeStack.Count == _rootLevel)
                {
                    if (contract.UnderlyingType != _rootContract.CreatedType)
                        return true;
                }
            }

            return false;
        }
		private bool ReadMetadataPropertiesToken (JTokenReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
		{
			id = null;
			newValue = null;

			if (reader.TokenType == JsonToken.StartObject) {
				JObject current = (JObject)reader._current;

				JToken refToken = current[JsonTypeReflector.RefPropertyName];
				if (refToken != null) {
					if (refToken.Type != JTokenType.String && refToken.Type != JTokenType.Null)
						throw JsonSerializationException.Create(refToken, refToken.Path, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null);

					JToken property = refToken.Parent;
					JToken additionalContent = null;
					if (property.Next != null)
						additionalContent = property.Next;
					else if (property.Previous != null)
						additionalContent = property.Previous;

					string reference = (string)refToken;

					if (reference != null) {
						if (additionalContent != null)
							throw JsonSerializationException.Create(additionalContent, additionalContent.Path, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null);

						newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference);

						if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
							TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);

						reader.Skip();
						return true;
					}
				}
				JToken typeToken = current[JsonTypeReflector.TypePropertyName];
				if (typeToken != null) {
					string qualifiedTypeName = (string)typeToken;
					JsonReader typeTokenReader = typeToken.CreateReader();
					CheckedRead(typeTokenReader);
					ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName);

					JToken valueToken = current[JsonTypeReflector.ValuePropertyName];
					if (valueToken != null) {
						while (true) {
							CheckedRead(reader);
							if (reader.TokenType == JsonToken.PropertyName) {
								if ((string)reader.Value == JsonTypeReflector.ValuePropertyName)
									return false;
							}

							CheckedRead(reader);
							reader.Skip();
						}
					}
				}
				JToken idToken = current[JsonTypeReflector.IdPropertyName];
				if (idToken != null) {
					id = (string)idToken;
				}
				JToken valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName];
				if (valuesToken != null) {
					JsonReader listReader = valuesToken.CreateReader();
					CheckedRead(listReader);
					newValue = CreateList(listReader, objectType, contract, member, existingValue, id);

					reader.Skip();
					return true;
				}
			}

			CheckedRead(reader);
			return false;
		}
        private string GetPropertyName(JsonWriter writer, object name, JsonContract contract, out bool escape)
        {
            string propertyName;

            if (contract.ContractType == JsonContractType.Primitive)
            {
                JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;
                if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTime || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeNullable)
                {
                    escape = false;
                    StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                    DateTimeUtils.WriteDateTimeString(sw, (DateTime)name, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
                    return sw.ToString();
                }
#if !NET20
                else if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeOffset || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeOffsetNullable)
                {
                    escape = false;
                    StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                    DateTimeUtils.WriteDateTimeOffsetString(sw, (DateTimeOffset)name, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
                    return sw.ToString();
                }
#endif
                else
                {
                    escape = true;
                    return Convert.ToString(name, CultureInfo.InvariantCulture);
                }
            }
            else if (TryConvertToString(name, name.GetType(), out propertyName))
            {
                escape = true;
                return propertyName;
            }
            else
            {
                escape = true;
                return name.ToString();
            }
        }
		private void ResolveTypeName (JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, string qualifiedTypeName)
		{
			TypeNameHandling resolvedTypeNameHandling =
				((member != null) ? member.TypeNameHandling : null)
				?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
				?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null)
				?? Serializer._typeNameHandling;

			if (resolvedTypeNameHandling != TypeNameHandling.None) {
				string typeName;
				string assemblyName;
				ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);

				Type specifiedType;
				try {
					specifiedType = Serializer._binder.BindToType(assemblyName, typeName);
				}
				catch (Exception ex) {
					throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
				}

				if (specifiedType == null)
					throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));

				if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
					TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved type '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName, specifiedType)), null);

				if (objectType != null && !objectType.IsAssignableFrom(specifiedType)) {
					throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
				}

				objectType = specifiedType;
				contract = GetContractSafe(specifiedType);
			}
		}
		private void ThrowUnexpectedEndException (JsonReader reader, JsonContract contract, object currentObject, string message)
		{
			try {
				throw JsonSerializationException.Create(reader, message);
			}
			catch (Exception ex) {
				if (IsErrorHandled(currentObject, contract, null, reader as IJsonLineInfo, reader.Path, ex))
					HandleError(reader, false, 0);
				else
					throw;
			}
		}
		private object CreateList (JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
		{
			object value;

			if (HasNoDefinedType(contract))
				return CreateJToken(reader, contract);

			JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract);

			if (existingValue == null) {
				bool createdFromNonDefaultCreator;
				IList list = CreateNewList(reader, arrayContract, out createdFromNonDefaultCreator);

				if (createdFromNonDefaultCreator) {
					if (id != null)
						throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

					if (contract.OnSerializingCallbacks.Count > 0)
						throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

					if (contract.OnErrorCallbacks.Count > 0)
						throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

					if (!arrayContract.HasParametrizedCreator && !arrayContract.IsArray)
						throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
				}

				if (!arrayContract.IsMultidimensionalArray)
					PopulateList(list, reader, arrayContract, member, id);
				else
					PopulateMultidimensionalArray(list, reader, arrayContract, member, id);

				if (createdFromNonDefaultCreator) {
					if (arrayContract.IsMultidimensionalArray) {
						list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType, contract.CreatedType.GetArrayRank());
					}
					else if (arrayContract.IsArray) {
						Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count);
						list.CopyTo(a, 0);
						list = a;
					}
					else {
						// call constructor that takes IEnumerable<T>
						return arrayContract.ParametrizedCreator(list);
					}
				}
				else if (list is IWrappedCollection) {
					return ((IWrappedCollection)list).UnderlyingCollection;
				}

				value = list;
			}
			else {
				value = PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(existingValue) : (IList)existingValue, reader, arrayContract, member, id);
			}

			return value;
		}
		private bool ReadForType (JsonReader reader, JsonContract contract, bool hasConverter)
		{
			// don't read properties with converters as a specific value
			// the value might be a string which will then get converted which will error if read as date for example
			if (hasConverter)
				return reader.Read();

			ReadType t = (contract != null) ? contract.InternalReadType : ReadType.Read;

			switch (t) {
			case ReadType.Read:
				do {
					if (!reader.Read())
						return false;
				} while (reader.TokenType == JsonToken.Comment);

				return true;
			case ReadType.ReadAsInt32:
				reader.ReadAsInt32();
				break;
			case ReadType.ReadAsDecimal:
				reader.ReadAsDecimal();
				break;
			case ReadType.ReadAsBytes:
				reader.ReadAsBytes();
				break;
			case ReadType.ReadAsString:
				reader.ReadAsString();
				break;
			case ReadType.ReadAsDateTime:
				reader.ReadAsDateTime();
				break;
#if !NET20
			case ReadType.ReadAsDateTimeOffset:
				reader.ReadAsDateTimeOffset();
				break;
#endif
			default:
				throw new ArgumentOutOfRangeException();
			}

			return (reader.TokenType != JsonToken.None);
		}
		private object EnsureType (JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType)
		{
			if (targetType == null)
				return value;

			Type valueType = ReflectionUtils.GetObjectType(value);

			// type of value and type of target don't match
			// attempt to convert value's type to target's type
			if (valueType != targetType) {
				if (value == null && contract.IsNullable)
					return null;

				try {
					if (contract.IsConvertable) {
						JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;

						if (contract.IsEnum) {
							if (value is string)
								return Enum.Parse(contract.NonNullableUnderlyingType, value.ToString(), true);
							if (ConvertUtils.IsInteger(primitiveContract.TypeCode))
								return Enum.ToObject(contract.NonNullableUnderlyingType, value);
						}
						#if NET40
						if (value is BigInteger)
						{
							return ConvertUtils.FromBigInteger((BigInteger)value, targetType);
						}
						#endif
						// this won't work when converting to a custom IConvertible
						return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture);
					}

					return ConvertUtils.ConvertOrCast(value, culture, contract.NonNullableUnderlyingType);
				}
				catch (Exception ex) {
					throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(value), targetType), ex);
				}
			}

			return value;
		}
		private JToken CreateJToken (JsonReader reader, JsonContract contract)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");

			if (contract != null) {
				if (contract.UnderlyingType == typeof(JRaw))
					return JRaw.Create(reader);
				if (reader.TokenType == JsonToken.Null
				                && !(contract.UnderlyingType == typeof(JValue) || contract.UnderlyingType == typeof(JToken)))
					return null;
			}

			JToken token;
			using (JTokenWriter writer = new JTokenWriter()) {
				writer.WriteToken(reader);
				token = writer.Token;
			}

			return token;
		}
		private void OnDeserializing (JsonReader reader, JsonContract contract, object value)
		{
			if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
				TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);

			contract.InvokeOnDeserializing(value, Serializer._context);
		}
        private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }

            JsonConverter converter = 
                ((member != null) ? member.Converter : null) ??
                ((containerProperty != null) ? containerProperty.ItemConverter : null) ??
                ((containerContract != null) ? containerContract.ItemConverter : null) ??
                valueContract.Converter ??
                Serializer.GetMatchingConverter(valueContract.UnderlyingType) ??
                valueContract.InternalConverter;

            if (converter != null && converter.CanWrite)
            {
                SerializeConvertable(writer, converter, value, valueContract, containerContract, containerProperty);
                return;
            }

            switch (valueContract.ContractType)
            {
                case JsonContractType.Object:
                    SerializeObject(writer, value, (JsonObjectContract)valueContract, member, containerContract, containerProperty);
                    break;
                case JsonContractType.Array:
                    JsonArrayContract arrayContract = (JsonArrayContract)valueContract;
                    if (!arrayContract.IsMultidimensionalArray)
                        SerializeList(writer, (IEnumerable)value, arrayContract, member, containerContract, containerProperty);
                    else
                        SerializeMultidimensionalArray(writer, (Array)value, arrayContract, member, containerContract, containerProperty);
                    break;
                case JsonContractType.Primitive:
                    SerializePrimitive(writer, value, (JsonPrimitiveContract)valueContract, member, containerContract, containerProperty);
                    break;
                case JsonContractType.String:
                    SerializeString(writer, value, (JsonStringContract)valueContract);
                    break;
                case JsonContractType.Dictionary:
                    JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)valueContract;
                    SerializeDictionary(writer, (value is IDictionary) ? (IDictionary)value : dictionaryContract.CreateWrapper(value), dictionaryContract, member, containerContract, containerProperty);
                    break;
                case JsonContractType.Serializable:
                    SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract, member, containerContract, containerProperty);
                    break;
                case JsonContractType.Linq:
                    ((JToken)value).WriteTo(writer, Serializer.Converters.ToArray());
                    break;
            }
        }