-Decreased deserializer stack usage

This commit is contained in:
James Newton-King
2012-05-06 01:43:20 +12:00
parent 2dfd0bc940
commit e4491e5812
5 changed files with 296 additions and 225 deletions
@@ -721,5 +721,33 @@ now brown cow?", '"', true);
Assert.AreEqual(@"""2000-01-01T01:01:01Z""", json);
}
//[Test]
public void StackOverflowTest()
{
StringBuilder sb = new StringBuilder();
int depth = 700;
for (int i = 0; i < depth; i++)
{
sb.Append("{'A':");
}
// invalid json
sb.Append("{***}");
for (int i = 0; i < depth; i++)
{
sb.Append("}");
}
string json = sb.ToString();
JsonSerializer serializer = new JsonSerializer() { };
serializer.Deserialize<Nest>(new JsonTextReader(new StringReader(json)));
}
public class Nest
{
public Nest A { get; set; }
}
}
}
@@ -72,5 +72,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
#if !PocketPC
[assembly: AssemblyFileVersion("4.5.4.14905")]
[assembly: AssemblyFileVersion("4.5.4.14906")]
#endif
@@ -90,7 +90,7 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
#if !PocketPC
[assembly: AssemblyFileVersion("4.5.4.14905")]
[assembly: AssemblyFileVersion("4.5.4.14906")]
#endif
[assembly: CLSCompliant(true)]
@@ -125,7 +125,10 @@ namespace Newtonsoft.Json.Serialization
return null;
}
return CreateValueNonProperty(reader, objectType, contract, converter, null, null);
if (converter != null && converter.CanRead)
return converter.ReadJson(reader, objectType, null, GetInternalSerializer());
return CreateValueInternal(reader, objectType, contract, null, null, null, null);
}
catch (Exception ex)
{
@@ -201,50 +204,6 @@ namespace Newtonsoft.Json.Serialization
return token;
}
private object CreateValueProperty(JsonReader reader, JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, object target, bool gottenCurrentValue, object currentValue)
{
JsonContract contract;
JsonConverter converter;
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
if (currentValue == null)
{
contract = property.PropertyContract;
converter = propertyConverter;
}
else
{
contract = GetContractSafe(currentValue.GetType());
if (contract != property.PropertyContract)
converter = GetConverter(contract, property.MemberConverter, containerContract, containerProperty);
else
converter = propertyConverter;
}
Type objectType = property.PropertyType;
if (converter != null && converter.CanRead)
{
if (!gottenCurrentValue && target != null && property.Readable)
currentValue = property.ValueProvider.GetValue(target);
return converter.ReadJson(reader, objectType, currentValue, GetInternalSerializer());
}
return CreateValueInternal(reader, objectType, contract, property, containerContract, containerProperty, currentValue);
}
private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract, JsonConverter converter, JsonContainerContract containerContract, JsonProperty containerProperty)
{
if (converter != null && converter.CanRead)
return converter.ReadJson(reader, objectType, null, GetInternalSerializer());
return CreateValueInternal(reader, objectType, contract, null, containerContract, containerProperty, 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)
@@ -337,7 +296,70 @@ namespace Newtonsoft.Json.Serialization
{
CheckedRead(reader);
string id = null;
string id;
object newValue;
if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
return newValue;
if (!HasDefinedType(objectType))
return CreateJObject(reader);
if (contract == null)
throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
switch (contract.ContractType)
{
case JsonContractType.Object:
JsonObjectContract objectContract = (JsonObjectContract) contract;
object targetObject;
if (existingValue != null)
targetObject = existingValue;
else
targetObject = CreateNewObject(reader, objectContract, member, containerMember, id);
return PopulateObject(targetObject, reader, objectContract, member, containerMember, id);
case JsonContractType.Primitive:
JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract) contract;
// if the content is inside $value then read past it
if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, null, existingValue);
CheckedRead(reader);
return value;
}
break;
case JsonContractType.Dictionary:
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
object targetDictionary;
if (existingValue != null)
targetDictionary = existingValue;
else
targetDictionary = CreateNewDictionary(reader, dictionaryContract);
return PopulateDictionary(dictionaryContract.CreateWrapper(targetDictionary), reader, dictionaryContract, member, containerMember, id);
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
case JsonContractType.Dynamic:
JsonDynamicContract dynamicContract = (JsonDynamicContract) contract;
return CreateDynamic(reader, dynamicContract, member, id);
#endif
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
case JsonContractType.Serializable:
JsonISerializableContract serializableContract = (JsonISerializableContract) contract;
return CreateISerializable(reader, serializableContract, id);
#endif
}
throw JsonSerializationException.Create(reader, @"Cannot deserialize JSON object (i.e. {{""name"":""value""}}) into type '{0}'.
The deserialized type should be a normal .NET type (i.e. not a primitive type like integer, not a collection type like an array or List<T>) or a dictionary type (i.e. Dictionary<TKey, TValue>).
To force JSON objects to deserialize add the JsonObjectAttribute to the type.".FormatWith(CultureInfo.InvariantCulture, objectType));
}
private bool ReadSpecialProperties(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)
{
@@ -368,7 +390,10 @@ namespace Newtonsoft.Json.Serialization
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));
return Serializer.ReferenceResolver.ResolveReference(this, reference);
{
newValue = Serializer.ReferenceResolver.ResolveReference(this, reference);
return true;
}
}
else
{
@@ -380,7 +405,8 @@ namespace Newtonsoft.Json.Serialization
CheckedRead(reader);
string qualifiedTypeName = reader.Value.ToString();
TypeNameHandling resolvedTypeNameHandling = ((member != null) ? member.TypeNameHandling : null)
TypeNameHandling resolvedTypeNameHandling =
((member != null) ? member.TypeNameHandling : null)
?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null)
?? Serializer.TypeNameHandling;
@@ -406,9 +432,9 @@ namespace Newtonsoft.Json.Serialization
if (objectType != null
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
&& objectType != typeof(IDynamicMetaObjectProvider)
&& objectType != typeof (IDynamicMetaObjectProvider)
#endif
&& !objectType.IsAssignableFrom(specifiedType))
&& !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;
@@ -433,7 +459,10 @@ namespace Newtonsoft.Json.Serialization
CheckedRead(reader);
object list = CreateList(reader, objectType, contract, member, containerMember, existingValue, id);
CheckedRead(reader);
return list;
{
newValue = list;
return true;
}
}
else
{
@@ -443,54 +472,7 @@ namespace Newtonsoft.Json.Serialization
&& reader.TokenType == JsonToken.PropertyName);
}
}
if (!HasDefinedType(objectType))
return CreateJObject(reader);
if (contract == null)
throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
switch (contract.ContractType)
{
case JsonContractType.Object:
JsonObjectContract objectContract = (JsonObjectContract) contract;
if (existingValue == null)
return CreateAndPopulateObject(reader, objectContract, member, containerMember, id);
return PopulateObject(existingValue, reader, objectContract, member, containerMember, id);
case JsonContractType.Primitive:
JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract) contract;
// if the content is inside $value then read past it
if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal))
{
CheckedRead(reader);
object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, null, existingValue);
CheckedRead(reader);
return value;
}
break;
case JsonContractType.Dictionary:
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
if (existingValue == null)
return CreateAndPopulateDictionary(reader, dictionaryContract, member, containerMember, id);
return PopulateDictionary(dictionaryContract.CreateWrapper(existingValue), reader, dictionaryContract, member, containerMember, id);
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
case JsonContractType.Dynamic:
JsonDynamicContract dynamicContract = (JsonDynamicContract) contract;
return CreateDynamic(reader, dynamicContract, member, id);
#endif
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
case JsonContractType.Serializable:
JsonISerializableContract serializableContract = (JsonISerializableContract) contract;
return CreateISerializable(reader, serializableContract, id);
#endif
}
throw JsonSerializationException.Create(reader, @"Cannot deserialize JSON object (i.e. {{""name"":""value""}}) into type '{0}'.
The deserialized type should be a normal .NET type (i.e. not a primitive type like integer, not a collection type like an array or List<T>) or a dictionary type (i.e. Dictionary<TKey, TValue>).
To force JSON objects to deserialize add the JsonObjectAttribute to the type.".FormatWith(CultureInfo.InvariantCulture, objectType));
return false;
}
private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
@@ -521,9 +503,41 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract);
if (existingValue == null)
value = CreateAndPopulateList(reader, reference, arrayContract, member, containerProperty);
{
bool isTemporaryListReference;
IList list = CollectionUtils.CreateList(contract.CreatedType, out isTemporaryListReference);
if (reference != null && isTemporaryListReference)
throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#if !PocketPC
if (contract.OnSerializing != null && isTemporaryListReference)
throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#endif
if (contract.OnError != null && isTemporaryListReference)
throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
PopulateList(arrayContract.CreateWrapper(list), reader, reference, arrayContract, member);
// create readonly and fixed sized collections using the temporary list
if (isTemporaryListReference)
{
if (contract.CreatedType.IsArray)
list = CollectionUtils.ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(contract.CreatedType));
else if (ReflectionUtils.InheritsGenericDefinition(contract.CreatedType, typeof(ReadOnlyCollection<>)))
list = (IList)ReflectionUtils.CreateInstance(contract.CreatedType, list);
}
else if (list is IWrappedCollection)
{
return ((IWrappedCollection)list).UnderlyingCollection;
}
value = list;
}
else
{
value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, reference, arrayContract, member);
}
}
else
{
@@ -594,57 +608,28 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
private void SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
{
if (property.Ignored)
{
reader.Skip();
object currentValue;
bool useExistingValue;
JsonContract propertyContract;
bool gottenCurrentValue;
if (CalculatePropertyDetails(property, ref propertyConverter, containerContract, containerProperty, reader, target, out useExistingValue, out currentValue, out propertyContract, out gottenCurrentValue))
return;
}
object currentValue = null;
bool useExistingValue = false;
bool gottenCurrentValue = false;
object value;
ObjectCreationHandling objectCreationHandling =
property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
&& property.Readable)
if (propertyConverter != null && propertyConverter.CanRead)
{
currentValue = property.ValueProvider.GetValue(target);
gottenCurrentValue = true;
if (!gottenCurrentValue && target != null && property.Readable)
currentValue = property.ValueProvider.GetValue(target);
useExistingValue = (currentValue != null
&& !property.PropertyType.IsArray
&& !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof (ReadOnlyCollection<>))
&& !property.PropertyType.IsValueType());
value = propertyConverter.ReadJson(reader, property.PropertyType, currentValue, GetInternalSerializer());
}
if (!property.Writable && !useExistingValue)
else
{
reader.Skip();
return;
value = CreateValueInternal(reader, property.PropertyType, propertyContract, property, containerContract, containerProperty, (useExistingValue) ? currentValue : null);
}
// 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 && reader.TokenType == JsonToken.Null)
{
reader.Skip();
return;
}
// 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)
&& JsonReader.IsPrimitiveToken(reader.TokenType)
&& MiscellaneousUtils.ValueEquals(reader.Value, property.DefaultValue))
{
reader.Skip();
return;
}
object existingValue = (useExistingValue) ? currentValue : null;
object value = CreateValueProperty(reader, property, propertyConverter, containerContract, containerProperty, target, gottenCurrentValue, existingValue);
// always set the value if useExistingValue is false,
// otherwise also set it if CreateValue returns a new value compared to the currentValue
// this could happen because of a JsonConverter against the type
@@ -658,6 +643,75 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
}
}
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)
{
reader.Skip();
return true;
}
ObjectCreationHandling objectCreationHandling =
property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
&& property.Readable)
{
currentValue = property.ValueProvider.GetValue(target);
gottenCurrentValue = true;
useExistingValue = (currentValue != null
&& !property.PropertyType.IsArray
&& !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof (ReadOnlyCollection<>))
&& !property.PropertyType.IsValueType());
}
if (!property.Writable && !useExistingValue)
{
reader.Skip();
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 && reader.TokenType == JsonToken.Null)
{
reader.Skip();
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)
&& JsonReader.IsPrimitiveToken(reader.TokenType)
&& MiscellaneousUtils.ValueEquals(reader.Value, property.DefaultValue))
{
reader.Skip();
return true;
}
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
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 HasFlag(DefaultValueHandling value, DefaultValueHandling flag)
{
return ((value & flag) == flag);
@@ -678,7 +732,7 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
return true;
}
private object CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, JsonProperty member, JsonProperty containerProperty, string id)
public object CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract)
{
object dictionary;
@@ -688,11 +742,7 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
else
throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
IWrappedDictionary dictionaryWrapper = contract.CreateWrapper(dictionary);
PopulateDictionary(dictionaryWrapper, reader, contract, member, containerProperty, id);
return dictionaryWrapper.UnderlyingDictionary;
return dictionary;
}
private object PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty member, JsonProperty containerProperty, string id)
@@ -732,7 +782,13 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
if (!ReadForType(reader, contract.ItemContract, dictionaryValueConverter != null, false))
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
dictionary[keyValue] = CreateValueNonProperty(reader, contract.DictionaryValueType, contract.ItemContract, dictionaryValueConverter, contract, member);
object itemValue;
if (dictionaryValueConverter != null && dictionaryValueConverter.CanRead)
itemValue = dictionaryValueConverter.ReadJson(reader, contract.DictionaryValueType, null, GetInternalSerializer());
else
itemValue = CreateValueInternal(reader, contract.DictionaryValueType, contract.ItemContract, null, contract, member, null);
dictionary[keyValue] = itemValue;
}
catch (Exception ex)
{
@@ -756,24 +812,6 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
}
private object CreateAndPopulateList(JsonReader reader, string reference, JsonArrayContract contract, JsonProperty member, JsonProperty containerProperty)
{
return CollectionUtils.CreateAndPopulateList(contract.CreatedType, (l, isTemporaryListReference) =>
{
if (reference != null && isTemporaryListReference)
throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#if !PocketPC
if (contract.OnSerializing != null && isTemporaryListReference)
throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#endif
if (contract.OnError != null && isTemporaryListReference)
throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
PopulateList(contract.CreateWrapper(l), reader, reference, contract, member);
});
}
private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, string reference, JsonArrayContract contract, JsonProperty containerProperty)
{
object list = wrappedList.UnderlyingCollection;
@@ -811,7 +849,12 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For
case JsonToken.Comment:
break;
default:
object value = CreateValueNonProperty(reader, contract.CollectionItemType, collectionItemContract, collectionItemConverter, contract, containerProperty);
object value;
if (collectionItemConverter != null && collectionItemConverter.CanRead)
value = collectionItemConverter.ReadJson(reader, contract.CollectionItemType, null, GetInternalSerializer());
else
value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
wrappedList.Add(value);
break;
@@ -942,7 +985,11 @@ To fix this error either change the environment to be fully trusted, change the
JsonContract dynamicMemberContract = GetContractSafe(t);
JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member);
object value = CreateValueNonProperty(reader, t, dynamicMemberContract, dynamicMemberConverter, null, member);
object value;
if (dynamicMemberConverter != null && dynamicMemberConverter.CanRead)
value = dynamicMemberConverter.ReadJson(reader, t, null, GetInternalSerializer());
else
value = CreateValueInternal(reader, t, dynamicMemberContract, null, null, member, null);
newObject.TrySetMember(memberName, value);
}
@@ -969,41 +1016,6 @@ To fix this error either change the environment to be fully trusted, change the
}
#endif
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, JsonProperty member, JsonProperty containerProperty, string id)
{
object newObject = null;
if (contract.UnderlyingType.IsInterface() || contract.UnderlyingType.IsAbstract())
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
if (contract.OverrideConstructor != null)
{
if (contract.OverrideConstructor.GetParameters().Length > 0)
return CreateObjectFromNonDefaultConstructor(reader, contract, containerProperty, contract.OverrideConstructor, id);
newObject = contract.OverrideConstructor.Invoke(null);
}
else if (contract.DefaultCreator != null &&
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || contract.ParametrizedConstructor == null))
{
// use the default constructor if it is...
// public
// non-public and the user has change constructor handling settings
// non-public and there is no other constructor
newObject = contract.DefaultCreator();
}
else if (contract.ParametrizedConstructor != null)
{
return CreateObjectFromNonDefaultConstructor(reader, contract, containerProperty, contract.ParametrizedConstructor, id);
}
if (newObject == null)
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
PopulateObject(newObject, reader, contract, member, containerProperty, id);
return newObject;
}
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, string id)
{
ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo");
@@ -1112,9 +1124,22 @@ To fix this error either change the environment to be fully trusted, change the
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
if (!property.Ignored)
propertyValues[property] = CreateValueProperty(reader, property, propertyConverter, contract, containerProperty, null, true, null);
{
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
object propertyValue;
if (propertyConverter != null && propertyConverter.CanRead)
propertyValue = propertyConverter.ReadJson(reader, property.PropertyType, null, GetInternalSerializer());
else
propertyValue = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null);
propertyValues[property] = propertyValue;
}
else
{
reader.Skip();
}
}
else
{
@@ -1186,6 +1211,40 @@ To fix this error either change the environment to be fully trusted, change the
return (reader.TokenType != JsonToken.None);
}
public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id)
{
object newObject = null;
if (objectContract.UnderlyingType.IsInterface() || objectContract.UnderlyingType.IsAbstract())
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
if (objectContract.OverrideConstructor != null)
{
if (objectContract.OverrideConstructor.GetParameters().Length > 0)
return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.OverrideConstructor, id);
newObject = objectContract.OverrideConstructor.Invoke(null);
}
else if (objectContract.DefaultCreator != null &&
(!objectContract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null))
{
// use the default constructor if it is...
// public
// non-public and the user has change constructor handling settings
// non-public and there is no other constructor
newObject = objectContract.DefaultCreator();
}
else if (objectContract.ParametrizedConstructor != null)
{
return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedConstructor, id);
}
if (newObject == null)
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
return newObject;
}
private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, JsonProperty containerProperty, string id)
{
contract.InvokeOnDeserializing(newObject, Serializer.Context);
@@ -171,14 +171,13 @@ namespace Newtonsoft.Json.Utilities
}
}
public static object CreateAndPopulateList(Type listType, Action<IList, bool> populateList)
public static IList CreateList(Type listType, out bool isReadOnlyOrFixedSize)
{
ValidationUtils.ArgumentNotNull(listType, "listType");
ValidationUtils.ArgumentNotNull(populateList, "populateList");
IList list;
Type collectionType;
bool isReadOnlyOrFixedSize = false;
isReadOnlyOrFixedSize = false;
if (listType.IsArray)
{
@@ -239,21 +238,6 @@ namespace Newtonsoft.Json.Utilities
if (list == null)
throw new InvalidOperationException("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
populateList(list, isReadOnlyOrFixedSize);
// create readonly and fixed sized collections using the temporary list
if (isReadOnlyOrFixedSize)
{
if (listType.IsArray)
list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(listType));
else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>)))
list = (IList)ReflectionUtils.CreateInstance(listType, list);
}
else if (list is IWrappedCollection)
{
return ((IWrappedCollection) list).UnderlyingCollection;
}
return list;
}