-Refactored serializing and deserializing lists and dictionary
This commit is contained in:
@@ -464,6 +464,8 @@ keyword such as type of business.""
|
||||
|
||||
string jsonText = JsonConvert.SerializeObject(r1);
|
||||
|
||||
Assert.AreEqual("[0,1,2,3,4]", jsonText);
|
||||
|
||||
ReadOnlyCollection<int> r2 = JsonConvert.DeserializeObject<ReadOnlyCollection<int>>(jsonText);
|
||||
|
||||
CollectionAssert.AreEqual(r1, r2);
|
||||
@@ -4260,8 +4262,8 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
string json = JsonConvert.SerializeObject(s1, Formatting.Indented);
|
||||
|
||||
ExceptionAssert.Throws<InvalidOperationException>(
|
||||
"Cannot create and populate list type " + classRef + ".",
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Cannot create and populate list type " + classRef + ". Path 'StringDictionaryProperty', line 2, position 32.",
|
||||
() =>
|
||||
{
|
||||
JsonConvert.DeserializeObject<StringDictionaryTestClass>(json);
|
||||
@@ -5311,6 +5313,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
{
|
||||
BusRun r = JsonConvert.DeserializeObject<BusRun>("{\"Departures\":[\"\\/Date(1309874148734-0400)\\/\",\"\\/Date(1309874148739-0400)\\/\",null],\"WheelchairAccessible\":true}");
|
||||
|
||||
Assert.AreEqual(typeof(List<DateTime?>), r.Departures.GetType());
|
||||
Assert.AreEqual(3, r.Departures.Count());
|
||||
Assert.IsNotNull(r.Departures.ElementAt(0));
|
||||
Assert.IsNotNull(r.Departures.ElementAt(1));
|
||||
@@ -6748,6 +6751,40 @@ Parameter name: value",
|
||||
Assert.AreEqual("3", result.ElementAt(2));
|
||||
}
|
||||
|
||||
public class EnumerableClassFailure<T> : IEnumerable<T>
|
||||
{
|
||||
private readonly IList<T> _values;
|
||||
|
||||
public EnumerableClassFailure()
|
||||
{
|
||||
_values = new List<T>();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return _values.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeIEnumerableFromConstructor_Failure()
|
||||
{
|
||||
string json = @"[
|
||||
""One"",
|
||||
""II"",
|
||||
""3""
|
||||
]";
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Cannot create and populate list type Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+EnumerableClassFailure`1[System.String]. Path '', line 1, position 1.",
|
||||
() => JsonConvert.DeserializeObject<EnumerableClassFailure<string>>(json));
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.Fields)]
|
||||
public class MyTuple<T1>
|
||||
{
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Collections;
|
||||
@@ -56,8 +58,33 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private readonly bool _isCollectionItemTypeNullableType;
|
||||
private readonly Type _genericCollectionDefinitionType;
|
||||
|
||||
private Type _genericWrapperType;
|
||||
private MethodCall<object, object> _genericWrapperCreator;
|
||||
private Func<object> _genericTemporaryCollectionCreator;
|
||||
|
||||
internal bool ShouldCreateWrapper { get; private set; }
|
||||
internal bool CanDeserialize { get; private set; }
|
||||
internal Type TemporaryCollectionType { get; private set; }
|
||||
internal bool IsReadOnlyOrFixedSize { get; private set; }
|
||||
|
||||
private ConstructorInfo ResolveReadOnlyCollectionConstructor(Type readOnlyCollectionType, Type collectionTypeType)
|
||||
{
|
||||
Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), collectionTypeType);
|
||||
|
||||
foreach (ConstructorInfo constructor in readOnlyCollectionType.GetConstructors())
|
||||
{
|
||||
IList<ParameterInfo> parameters = constructor.GetParameters();
|
||||
|
||||
if (parameters.Count == 1)
|
||||
{
|
||||
if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
|
||||
@@ -67,27 +94,74 @@ namespace Newtonsoft.Json.Serialization
|
||||
: base(underlyingType)
|
||||
{
|
||||
ContractType = JsonContractType.Array;
|
||||
|
||||
if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType))
|
||||
|
||||
bool canDeserialize;
|
||||
|
||||
Type tempCollectionType;
|
||||
if (CreatedType.IsArray)
|
||||
{
|
||||
CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
|
||||
IsReadOnlyOrFixedSize = true;
|
||||
|
||||
canDeserialize = true;
|
||||
TemporaryCollectionType = typeof (List<object>);
|
||||
}
|
||||
else if (ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyCollection<>), out tempCollectionType))
|
||||
{
|
||||
CollectionItemType = tempCollectionType.GetGenericArguments()[0];
|
||||
IsReadOnlyOrFixedSize = true;
|
||||
|
||||
canDeserialize = (ResolveReadOnlyCollectionConstructor(underlyingType, CollectionItemType) != null);
|
||||
TemporaryCollectionType = ReflectionUtils.MakeGenericType(typeof(List<>), CollectionItemType);
|
||||
}
|
||||
else if (typeof(IList).IsAssignableFrom(underlyingType))
|
||||
{
|
||||
if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType))
|
||||
CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0];
|
||||
else
|
||||
CollectionItemType = ReflectionUtils.GetCollectionItemType(underlyingType);
|
||||
|
||||
canDeserialize = true;
|
||||
}
|
||||
else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType))
|
||||
{
|
||||
CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0];
|
||||
canDeserialize = true;
|
||||
ShouldCreateWrapper = true;
|
||||
}
|
||||
else if (underlyingType.IsGenericType() && underlyingType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
{
|
||||
_genericCollectionDefinitionType = typeof (IEnumerable<>);
|
||||
_genericCollectionDefinitionType = typeof(IEnumerable<>);
|
||||
CollectionItemType = underlyingType.GetGenericArguments()[0];
|
||||
|
||||
IsReadOnlyOrFixedSize = true;
|
||||
canDeserialize = true;
|
||||
}
|
||||
else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out tempCollectionType))
|
||||
{
|
||||
CollectionItemType = tempCollectionType.GetGenericArguments()[0];
|
||||
|
||||
IsReadOnlyOrFixedSize = true;
|
||||
canDeserialize = (ResolveReadOnlyCollectionConstructor(underlyingType, CollectionItemType) != null);
|
||||
TemporaryCollectionType = ReflectionUtils.MakeGenericType(typeof(List<>), CollectionItemType);
|
||||
}
|
||||
#if !(NET40 || NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE || PORTABLE)
|
||||
else if (underlyingType.IsGenericType() && underlyingType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>))
|
||||
{
|
||||
CollectionItemType = underlyingType.GetGenericArguments()[0];
|
||||
IsReadOnlyOrFixedSizeCollection = true;
|
||||
|
||||
_readOnlyCollectionConstructor = ResolveReadOnlyCollectionConstructor(underlyingType, CollectionItemType);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
|
||||
// types that implement IEnumerable and nothing else
|
||||
canDeserialize = false;
|
||||
}
|
||||
|
||||
CanDeserialize = canDeserialize;
|
||||
|
||||
if (CollectionItemType != null)
|
||||
_isCollectionItemTypeNullableType = ReflectionUtils.IsNullableType(CollectionItemType);
|
||||
|
||||
@@ -102,6 +176,17 @@ namespace Newtonsoft.Json.Serialization
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(HashSet<>), CollectionItemType);
|
||||
#endif
|
||||
|
||||
#if (NET20 || NET35)
|
||||
// bug in .NET 2.0 & 3.5 that List<Nullable<T>> throws an error when adding null via IList.Add(object)
|
||||
// wrapper will handle calling Add(T) instead
|
||||
if (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(List<>), out tempCollectionType))
|
||||
{
|
||||
Type tempCollectionItemType = tempCollectionType.GetGenericArguments()[0];
|
||||
if (ReflectionUtils.IsNullableType(tempCollectionItemType))
|
||||
_createWrapper = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
IsMultidimensionalArray = (UnderlyingType.IsArray && UnderlyingType.GetArrayRank() > 1);
|
||||
}
|
||||
|
||||
@@ -135,6 +220,14 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
internal IList CreateTemporaryCollection()
|
||||
{
|
||||
if (_genericTemporaryCollectionCreator == null)
|
||||
_genericTemporaryCollectionCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(TemporaryCollectionType);
|
||||
|
||||
return (IList)_genericTemporaryCollectionCreator();
|
||||
}
|
||||
|
||||
private void EnsureGenericWrapperCreator()
|
||||
{
|
||||
if (_genericWrapperCreator == null)
|
||||
|
||||
@@ -67,6 +67,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private Func<object> _genericTemporaryDictionaryCreator;
|
||||
|
||||
internal bool ShouldCreateWrapper { get; private set; }
|
||||
internal bool IsReadOnlyOrFixedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
|
||||
/// </summary>
|
||||
@@ -78,6 +81,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
Type keyType;
|
||||
Type valueType;
|
||||
|
||||
if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType))
|
||||
{
|
||||
keyType = _genericCollectionDefinitionType.GetGenericArguments()[0];
|
||||
@@ -88,6 +92,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
keyType = _genericCollectionDefinitionType.GetGenericArguments()[0];
|
||||
valueType = _genericCollectionDefinitionType.GetGenericArguments()[1];
|
||||
|
||||
IsReadOnlyOrFixedSize = true;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
@@ -95,6 +101,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType);
|
||||
}
|
||||
|
||||
ShouldCreateWrapper = !typeof (IDictionary).IsAssignableFrom(underlyingType);
|
||||
|
||||
DictionaryKeyType = keyType;
|
||||
DictionaryValueType = valueType;
|
||||
|
||||
@@ -108,7 +116,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
#if !(NET40 || NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE || PORTABLE)
|
||||
else if (IsTypeGenericReadOnlyDictionaryInterface(UnderlyingType))
|
||||
{
|
||||
IsReadOnlyDictionary = true;
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(ReadOnlyDictionary<,>), keyType, valueType);
|
||||
}
|
||||
#endif
|
||||
@@ -134,7 +141,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
return (IWrappedDictionary)_genericWrapperCreator(null, dictionary);
|
||||
}
|
||||
|
||||
internal object CreateTemporaryDictionary()
|
||||
internal IDictionary CreateTemporaryDictionary()
|
||||
{
|
||||
if (_genericTemporaryDictionaryCreator == null)
|
||||
{
|
||||
@@ -143,7 +150,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
_genericTemporaryDictionaryCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(temporaryDictionaryType);
|
||||
}
|
||||
|
||||
return _genericTemporaryDictionaryCreator();
|
||||
return (IDictionary)_genericTemporaryDictionaryCreator();
|
||||
}
|
||||
|
||||
private bool IsTypeGenericDictionaryInterface(Type type)
|
||||
@@ -167,7 +174,5 @@ namespace Newtonsoft.Json.Serialization
|
||||
return (genericDefinition == typeof(IReadOnlyDictionary<,>));
|
||||
}
|
||||
#endif
|
||||
|
||||
internal bool IsReadOnlyDictionary { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -81,9 +81,15 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
if (contract.ContractType == JsonContractType.Array)
|
||||
PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, (JsonArrayContract) contract, null, null);
|
||||
{
|
||||
JsonArrayContract arrayContract = (JsonArrayContract) contract;
|
||||
|
||||
PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(target) : (IList)target, reader, arrayContract, null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
}
|
||||
else if (reader.TokenType == JsonToken.StartObject)
|
||||
{
|
||||
@@ -98,11 +104,18 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
|
||||
if (contract.ContractType == JsonContractType.Dictionary)
|
||||
PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader, (JsonDictionaryContract) contract, null, id);
|
||||
{
|
||||
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)contract;
|
||||
PopulateDictionary((dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(target) : (IDictionary)target, reader, dictionaryContract, null, id);
|
||||
}
|
||||
else if (contract.ContractType == JsonContractType.Object)
|
||||
{
|
||||
PopulateObject(target, reader, (JsonObjectContract) contract, null, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -389,21 +402,17 @@ namespace Newtonsoft.Json.Serialization
|
||||
break;
|
||||
case JsonContractType.Dictionary:
|
||||
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
|
||||
bool isTemporaryDictionary = false;
|
||||
object targetDictionary;
|
||||
if (existingValue != null)
|
||||
targetDictionary = existingValue;
|
||||
targetDictionary = dictionaryContract.ShouldCreateWrapper ? dictionaryContract.CreateWrapper(existingValue) : existingValue;
|
||||
else
|
||||
targetDictionary = CreateNewDictionary(reader, dictionaryContract, out isTemporaryDictionary);
|
||||
targetDictionary = CreateNewDictionary(reader, dictionaryContract);
|
||||
|
||||
object dictionary = PopulateDictionary(dictionaryContract.CreateWrapper(targetDictionary), reader, dictionaryContract, member, id);
|
||||
object dictionary = PopulateDictionary((IDictionary) targetDictionary, reader, dictionaryContract, member, id);
|
||||
|
||||
if (isTemporaryDictionary)
|
||||
if (dictionaryContract.IsReadOnlyOrFixedSize)
|
||||
{
|
||||
if (dictionaryContract.IsReadOnlyDictionary)
|
||||
{
|
||||
dictionary = ReflectionUtils.CreateInstance(contract.CreatedType, dictionary);
|
||||
}
|
||||
dictionary = ReflectionUtils.CreateInstance(contract.CreatedType, dictionary);
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
@@ -575,37 +584,33 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
|
||||
if (existingValue == null)
|
||||
{
|
||||
bool isTemporaryListReference;
|
||||
IList list = CollectionUtils.CreateList(contract.CreatedType, out isTemporaryListReference);
|
||||
|
||||
if (id != null && isTemporaryListReference)
|
||||
if (id != null && arrayContract.IsReadOnlyOrFixedSize)
|
||||
throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
if (contract.OnSerializingCallbacks.Count > 0 && isTemporaryListReference)
|
||||
if (contract.OnSerializingCallbacks.Count > 0 && arrayContract.IsReadOnlyOrFixedSize)
|
||||
throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
if (contract.OnErrorCallbacks.Count > 0 && isTemporaryListReference)
|
||||
if (contract.OnErrorCallbacks.Count > 0 && arrayContract.IsReadOnlyOrFixedSize)
|
||||
throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
IList list = CreateNewList(reader, arrayContract);
|
||||
|
||||
if (!arrayContract.IsMultidimensionalArray)
|
||||
PopulateList(arrayContract.CreateWrapper(list), reader, arrayContract, member, id);
|
||||
PopulateList(list, reader, arrayContract, member, id);
|
||||
else
|
||||
PopulateMultidimensionalArray(list, reader, arrayContract, member, id);
|
||||
|
||||
// create readonly and fixed sized collections using the temporary list
|
||||
if (isTemporaryListReference)
|
||||
// not needed for IEnumerable<T> properties. temp list is final
|
||||
if (arrayContract.IsReadOnlyOrFixedSize && list.GetType() != contract.CreatedType)
|
||||
{
|
||||
if (arrayContract.IsMultidimensionalArray)
|
||||
{
|
||||
list = CollectionUtils.ToMultidimensionalArray(list, ReflectionUtils.GetCollectionItemType(contract.CreatedType), contract.CreatedType.GetArrayRank());
|
||||
list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType, contract.CreatedType.GetArrayRank());
|
||||
}
|
||||
else 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);
|
||||
list = CollectionUtils.ToArray(((List<object>)list).ToArray(), arrayContract.CollectionItemType);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -621,7 +626,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
}
|
||||
else
|
||||
{
|
||||
value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, arrayContract, member, id);
|
||||
value = PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(existingValue) : (IList) existingValue, reader, arrayContract, member, id);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -832,26 +837,47 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
return true;
|
||||
}
|
||||
|
||||
public object CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract, out bool isTemporaryDictionary)
|
||||
private IList CreateNewList(JsonReader reader, JsonArrayContract contract)
|
||||
{
|
||||
if (!contract.CanDeserialize)
|
||||
throw JsonSerializationException.Create(reader, "Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.CreatedType));
|
||||
|
||||
if (contract.IsReadOnlyOrFixedSize && contract.TemporaryCollectionType != null)
|
||||
{
|
||||
return contract.CreateTemporaryCollection();
|
||||
}
|
||||
else
|
||||
{
|
||||
object list = contract.DefaultCreator();
|
||||
|
||||
if (contract.ShouldCreateWrapper)
|
||||
list = contract.CreateWrapper(list);
|
||||
|
||||
return (IList)list;
|
||||
}
|
||||
}
|
||||
|
||||
private IDictionary CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract)
|
||||
{
|
||||
object dictionary;
|
||||
|
||||
if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
|
||||
{
|
||||
dictionary = contract.DefaultCreator();
|
||||
isTemporaryDictionary = false;
|
||||
}
|
||||
else if (contract.IsReadOnlyDictionary)
|
||||
if (contract.IsReadOnlyOrFixedSize)
|
||||
{
|
||||
dictionary = contract.CreateTemporaryDictionary();
|
||||
isTemporaryDictionary = true;
|
||||
}
|
||||
else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
|
||||
{
|
||||
dictionary = contract.DefaultCreator();
|
||||
|
||||
if (contract.ShouldCreateWrapper)
|
||||
dictionary = contract.CreateWrapper(dictionary);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
return (IDictionary)dictionary;
|
||||
}
|
||||
|
||||
private void OnDeserializing(JsonReader reader, JsonContract contract, object value)
|
||||
@@ -870,14 +896,15 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
contract.InvokeOnDeserialized(value, Serializer.Context);
|
||||
}
|
||||
|
||||
private object PopulateDictionary(IWrappedDictionary wrappedDictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id)
|
||||
private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id)
|
||||
{
|
||||
object dictionary = wrappedDictionary.UnderlyingDictionary;
|
||||
IWrappedDictionary wrappedDictionary = dictionary as IWrappedDictionary;
|
||||
object underlyingDictionary = wrappedDictionary != null ? wrappedDictionary.UnderlyingDictionary : dictionary;
|
||||
|
||||
if (id != null)
|
||||
AddReference(reader, id, dictionary);
|
||||
AddReference(reader, id, underlyingDictionary);
|
||||
|
||||
OnDeserializing(reader, contract, dictionary);
|
||||
OnDeserializing(reader, contract, underlyingDictionary);
|
||||
|
||||
int initialDepth = reader.Depth;
|
||||
|
||||
@@ -900,6 +927,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
{
|
||||
try
|
||||
{
|
||||
// this is for correctly reading ISO and MS formatted dictionary keys
|
||||
if (contract.DictionaryKeyType == typeof(DateTime) && JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTime, reader.DateTimeZoneHandling, out keyValue))
|
||||
{
|
||||
}
|
||||
@@ -927,11 +955,11 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
else
|
||||
itemValue = CreateValueInternal(reader, contract.DictionaryValueType, contract.ItemContract, null, contract, containerProperty, null);
|
||||
|
||||
wrappedDictionary[keyValue] = itemValue;
|
||||
dictionary[keyValue] = itemValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(dictionary, contract, keyValue, reader as IJsonLineInfo, reader.Path, ex))
|
||||
if (IsErrorHandled(underlyingDictionary, contract, keyValue, reader as IJsonLineInfo, reader.Path, ex))
|
||||
HandleError(reader, true, initialDepth);
|
||||
else
|
||||
throw;
|
||||
@@ -948,10 +976,10 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
} while (!finished && reader.Read());
|
||||
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, dictionary, "Unexpected end when deserializing object.");
|
||||
ThrowUnexpectedEndException(reader, contract, underlyingDictionary, "Unexpected end when deserializing object.");
|
||||
|
||||
OnDeserialized(reader, contract, dictionary);
|
||||
return dictionary;
|
||||
OnDeserialized(reader, contract, underlyingDictionary);
|
||||
return underlyingDictionary;
|
||||
}
|
||||
|
||||
private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
@@ -1092,21 +1120,22 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
}
|
||||
}
|
||||
|
||||
private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
{
|
||||
object list = wrappedList.UnderlyingCollection;
|
||||
IWrappedCollection wrappedCollection = list as IWrappedCollection;
|
||||
object underlyingList = wrappedCollection != null ? wrappedCollection.UnderlyingCollection : list;
|
||||
|
||||
if (id != null)
|
||||
AddReference(reader, id, list);
|
||||
AddReference(reader, id, underlyingList);
|
||||
|
||||
// can't populate an existing array
|
||||
if (wrappedList.IsFixedSize)
|
||||
if (list.IsFixedSize)
|
||||
{
|
||||
reader.Skip();
|
||||
return list;
|
||||
return underlyingList;
|
||||
}
|
||||
|
||||
OnDeserializing(reader, contract, list);
|
||||
OnDeserializing(reader, contract, underlyingList);
|
||||
|
||||
int initialDepth = reader.Depth;
|
||||
|
||||
@@ -1137,7 +1166,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
else
|
||||
value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
|
||||
|
||||
wrappedList.Add(value);
|
||||
list.Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1150,7 +1179,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
{
|
||||
JsonPosition errorPosition = reader.GetPosition(initialDepth);
|
||||
|
||||
if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
|
||||
if (IsErrorHandled(underlyingList, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
|
||||
{
|
||||
HandleError(reader, true, initialDepth);
|
||||
|
||||
@@ -1173,10 +1202,10 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
} while (!finished);
|
||||
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
|
||||
ThrowUnexpectedEndException(reader, contract, underlyingList, "Unexpected end when deserializing array.");
|
||||
|
||||
OnDeserialized(reader, contract, list);
|
||||
return list;
|
||||
OnDeserialized(reader, contract, underlyingList);
|
||||
return underlyingList;
|
||||
}
|
||||
|
||||
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
case JsonContractType.Array:
|
||||
JsonArrayContract arrayContract = (JsonArrayContract) valueContract;
|
||||
if (!arrayContract.IsMultidimensionalArray)
|
||||
SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, containerContract, containerProperty);
|
||||
SerializeList(writer, (value.ShouldCreateWrapper) ? arrayContract.CreateWrapper(value) : (IList) value, arrayContract, member, containerContract, containerProperty);
|
||||
else
|
||||
SerializeMultidimensionalArray(writer, (Array)value, arrayContract, member, containerContract, containerProperty);
|
||||
break;
|
||||
@@ -520,13 +520,16 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
private void SerializeList(JsonWriter writer, IList values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
{
|
||||
OnSerializing(writer, contract, values.UnderlyingCollection);
|
||||
IWrappedCollection wrappedCollection = values as IWrappedCollection;
|
||||
object underlyingList = wrappedCollection != null ? wrappedCollection.UnderlyingCollection : values;
|
||||
|
||||
_serializeStack.Add(values.UnderlyingCollection);
|
||||
OnSerializing(writer, contract, underlyingList);
|
||||
|
||||
bool hasWrittenMetadataObject = WriteStartArray(writer, values.UnderlyingCollection, contract, member, collectionContract, containerProperty);
|
||||
_serializeStack.Add(underlyingList);
|
||||
|
||||
bool hasWrittenMetadataObject = WriteStartArray(writer, underlyingList, contract, member, collectionContract, containerProperty);
|
||||
|
||||
writer.WriteStartArray();
|
||||
|
||||
@@ -554,7 +557,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(values.UnderlyingCollection, contract, index, null, writer.ContainerPath, ex))
|
||||
if (IsErrorHandled(underlyingList, contract, index, null, writer.ContainerPath, ex))
|
||||
HandleError(writer, initialDepth);
|
||||
else
|
||||
throw;
|
||||
@@ -572,7 +575,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
_serializeStack.RemoveAt(_serializeStack.Count - 1);
|
||||
|
||||
OnSerialized(writer, contract, values.UnderlyingCollection);
|
||||
OnSerialized(writer, contract, underlyingList);
|
||||
}
|
||||
|
||||
private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
@@ -817,22 +820,22 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
|
||||
{
|
||||
OnSerializing(writer, contract, values.UnderlyingDictionary);
|
||||
_serializeStack.Add(values.UnderlyingDictionary);
|
||||
IWrappedDictionary wrappedDictionary = values as IWrappedDictionary;
|
||||
object underlyingDictionary = wrappedDictionary != null ? wrappedDictionary.UnderlyingDictionary : values;
|
||||
|
||||
WriteObjectStart(writer, values.UnderlyingDictionary, contract, member, collectionContract, containerProperty);
|
||||
OnSerializing(writer, contract, underlyingDictionary);
|
||||
_serializeStack.Add(underlyingDictionary);
|
||||
|
||||
WriteObjectStart(writer, underlyingDictionary, contract, member, collectionContract, containerProperty);
|
||||
|
||||
if (contract.ItemContract == null)
|
||||
contract.ItemContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object));
|
||||
|
||||
int initialDepth = writer.Top;
|
||||
|
||||
// Mono Unity 3.0 fix
|
||||
IWrappedDictionary d = values;
|
||||
|
||||
foreach (DictionaryEntry entry in d)
|
||||
foreach (DictionaryEntry entry in values)
|
||||
{
|
||||
bool escape;
|
||||
string propertyName = GetPropertyName(writer, entry, out escape);
|
||||
@@ -863,7 +866,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(values.UnderlyingDictionary, contract, propertyName, null, writer.ContainerPath, ex))
|
||||
if (IsErrorHandled(underlyingDictionary, contract, propertyName, null, writer.ContainerPath, ex))
|
||||
HandleError(writer, initialDepth);
|
||||
else
|
||||
throw;
|
||||
@@ -874,7 +877,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
_serializeStack.RemoveAt(_serializeStack.Count - 1);
|
||||
|
||||
OnSerialized(writer, contract, values.UnderlyingDictionary);
|
||||
OnSerialized(writer, contract, underlyingDictionary);
|
||||
}
|
||||
|
||||
private string GetPropertyName(JsonWriter writer, DictionaryEntry entry, out bool escape)
|
||||
|
||||
@@ -171,102 +171,6 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public static IList CreateList(Type listType, out bool isReadOnlyOrFixedSize)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(listType, "listType");
|
||||
|
||||
IList list;
|
||||
Type collectionType;
|
||||
isReadOnlyOrFixedSize = false;
|
||||
|
||||
if (listType.IsArray)
|
||||
{
|
||||
// have to use an arraylist when creating array
|
||||
// there is no way to know the size until it is finised
|
||||
list = new List<object>();
|
||||
isReadOnlyOrFixedSize = true;
|
||||
}
|
||||
else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>), out collectionType))
|
||||
{
|
||||
Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
|
||||
Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
|
||||
bool suitableConstructor = false;
|
||||
|
||||
foreach (ConstructorInfo constructor in listType.GetConstructors())
|
||||
{
|
||||
IList<ParameterInfo> parameters = constructor.GetParameters();
|
||||
|
||||
if (parameters.Count == 1)
|
||||
{
|
||||
if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
|
||||
{
|
||||
suitableConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!suitableConstructor)
|
||||
throw new Exception("Read-only type {0} does not have a public constructor that takes a type that implements {1}.".FormatWith(CultureInfo.InvariantCulture, listType, genericEnumerable));
|
||||
|
||||
// can't add or modify a readonly list
|
||||
// use List<T> and convert once populated
|
||||
list = CreateGenericList(readOnlyCollectionContentsType);
|
||||
isReadOnlyOrFixedSize = true;
|
||||
}
|
||||
else if (typeof(IList).IsAssignableFrom(listType))
|
||||
{
|
||||
if (ReflectionUtils.IsInstantiatableType(listType))
|
||||
list = (IList)Activator.CreateInstance(listType);
|
||||
else if (listType == typeof(IList))
|
||||
list = new List<object>();
|
||||
else
|
||||
list = null;
|
||||
}
|
||||
else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof(ICollection<>)))
|
||||
{
|
||||
if (ReflectionUtils.IsInstantiatableType(listType))
|
||||
list = CreateCollectionWrapper(Activator.CreateInstance(listType));
|
||||
else
|
||||
list = null;
|
||||
}
|
||||
else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof (IEnumerable<>), out collectionType))
|
||||
{
|
||||
bool suitableConstructor = false;
|
||||
|
||||
foreach (ConstructorInfo constructor in listType.GetConstructors())
|
||||
{
|
||||
IList<ParameterInfo> parameters = constructor.GetParameters();
|
||||
|
||||
if (parameters.Count == 1)
|
||||
{
|
||||
if (collectionType.IsAssignableFrom(parameters[0].ParameterType))
|
||||
{
|
||||
suitableConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!suitableConstructor)
|
||||
throw new Exception("{0} does not have a public constructor that takes a type that implements {1}.".FormatWith(CultureInfo.InvariantCulture, listType, collectionType));
|
||||
|
||||
Type collectionContentsType = collectionType.GetGenericArguments()[0];
|
||||
|
||||
list = CreateGenericList(collectionContentsType);
|
||||
isReadOnlyOrFixedSize = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = null;
|
||||
}
|
||||
|
||||
if (list == null)
|
||||
throw new InvalidOperationException("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static Array ToArray(Array initial, Type type)
|
||||
{
|
||||
if (type == null)
|
||||
|
||||
Reference in New Issue
Block a user