-Added JsonConstructorAttribute support for lists and dictionaries

This commit is contained in:
James Newton-King
2015-10-03 14:10:39 +13:00
parent 352c9e0e9f
commit ad68ea8780
22 changed files with 477 additions and 83 deletions
@@ -2,7 +2,7 @@
<topic id="QueryJsonSelectTokenEscaped" revisionNumber="1">
<developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
<introduction>
<para>This sample loads JSON with properties that required escaped queries using <codeEntityReference>M:Newtonsoft.Json.Linq.JToken.SelectToken(System.String)</codeEntityReference>.</para>
<para>This sample loads JSON with properties that need to be escaped when queried with <codeEntityReference>M:Newtonsoft.Json.Linq.JToken.SelectToken(System.String)</codeEntityReference>.</para>
</introduction>
<section>
<title>Sample</title>
+1
View File
@@ -146,6 +146,7 @@
<codeEntityReference>T:Newtonsoft.Json.JsonPropertyAttribute</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonConverterAttribute</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonExtensionDataAttribute</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonConstructorAttribute</codeEntityReference>
</relatedTopics>
</developerConceptualDocument>
</topic>
@@ -203,7 +203,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.IsFalse(contract.IsInstantiable);
Assert.IsNull(contract.DefaultCreator);
Assert.IsFalse(contract.HasParametrizedCreator);
Assert.IsFalse(contract.HasParameterizedCreatorInternal);
ExceptionAssert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<AbstractListTestClass<int>>(@"[1,2]", new JsonSerializerSettings
{
@@ -283,7 +283,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.IsFalse(contract.IsInstantiable);
Assert.IsNull(contract.DefaultCreator);
Assert.IsFalse(contract.HasParametrizedCreator);
Assert.IsFalse(contract.HasParameterizedCreatorInternal);
ExceptionAssert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<AbstractDictionaryTestClass<string, int>>(@"{key1:1,key2:2}", new JsonSerializerSettings
{
@@ -436,13 +436,13 @@ namespace Newtonsoft.Json.Tests.Serialization
}
[Test]
public void ParametrizedCreator()
public void ParameterizedCreator()
{
var resolver = new DefaultContractResolver();
var contract = (JsonObjectContract)resolver.ResolveContract(typeof(PublicParametizedConstructorWithPropertyNameConflictWithAttribute));
Assert.IsNull(contract.DefaultCreator);
Assert.IsNotNull(contract.ParametrizedCreator);
Assert.IsNotNull(contract.ParameterizedCreator);
#pragma warning disable 618
Assert.AreEqual(contract.ParametrizedConstructor, typeof(PublicParametizedConstructorWithPropertyNameConflictWithAttribute).GetConstructor(new[] { typeof(string) }));
#pragma warning restore 618
@@ -452,7 +452,7 @@ namespace Newtonsoft.Json.Tests.Serialization
#pragma warning disable 618
contract.ParametrizedConstructor = null;
#pragma warning restore 618
Assert.IsNull(contract.ParametrizedCreator);
Assert.IsNull(contract.ParameterizedCreator);
}
[Test]
@@ -59,6 +59,248 @@ namespace Newtonsoft.Json.Tests.Serialization
[TestFixture]
public class JsonSerializerCollectionsTests : TestFixtureBase
{
public class TestCollectionPrivateParameterized : IEnumerable<int>
{
private readonly List<int> _bars;
public TestCollectionPrivateParameterized()
{
_bars = new List<int>();
}
[JsonConstructor]
private TestCollectionPrivateParameterized(IEnumerable<int> bars)
{
_bars = new List<int>(bars);
}
public void Add(int bar)
{
_bars.Add(bar);
}
public IEnumerator<int> GetEnumerator() => _bars.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
[Test]
public void CollectionJsonConstructorPrivateParameterized()
{
TestCollectionPrivateParameterized c1 = new TestCollectionPrivateParameterized();
c1.Add(0);
c1.Add(1);
c1.Add(2);
string json = JsonConvert.SerializeObject(c1);
TestCollectionPrivateParameterized c2 = JsonConvert.DeserializeObject<TestCollectionPrivateParameterized>(json);
List<int> values = c2.ToList();
Assert.AreEqual(3, values.Count);
Assert.AreEqual(0, values[0]);
Assert.AreEqual(1, values[1]);
Assert.AreEqual(2, values[2]);
}
public class TestCollectionPrivate : List<int>
{
[JsonConstructor]
private TestCollectionPrivate()
{
}
public static TestCollectionPrivate Create()
{
return new TestCollectionPrivate();
}
}
[Test]
public void CollectionJsonConstructorPrivate()
{
TestCollectionPrivate c1 = TestCollectionPrivate.Create();
c1.Add(0);
c1.Add(1);
c1.Add(2);
string json = JsonConvert.SerializeObject(c1);
TestCollectionPrivate c2 = JsonConvert.DeserializeObject<TestCollectionPrivate>(json);
List<int> values = c2.ToList();
Assert.AreEqual(3, values.Count);
Assert.AreEqual(0, values[0]);
Assert.AreEqual(1, values[1]);
Assert.AreEqual(2, values[2]);
}
public class TestCollectionMultipleParameters : List<int>
{
[JsonConstructor]
public TestCollectionMultipleParameters(string s1, string s2)
{
}
}
[Test]
public void CollectionJsonConstructorMultipleParameters()
{
ExceptionAssert.Throws<JsonException>(
() => JsonConvert.SerializeObject(new TestCollectionMultipleParameters(null, null)),
"Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestCollectionMultipleParameters' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Int32]'.");
}
public class TestCollectionBadIEnumerableParameter : List<int>
{
[JsonConstructor]
public TestCollectionBadIEnumerableParameter(List<string> l)
{
}
}
[Test]
public void CollectionJsonConstructorBadIEnumerableParameter()
{
ExceptionAssert.Throws<JsonException>(
() => JsonConvert.SerializeObject(new TestCollectionBadIEnumerableParameter(null)),
"Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestCollectionBadIEnumerableParameter' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Int32]'.");
}
#if !(DNXCORE50 || PORTABLE)
public class TestCollectionNonGeneric : ArrayList
{
[JsonConstructor]
public TestCollectionNonGeneric(IEnumerable l)
: base(l.Cast<object>().ToList())
{
}
}
[Test]
public void CollectionJsonConstructorNonGeneric()
{
string json = @"[1,2,3]";
TestCollectionNonGeneric l = JsonConvert.DeserializeObject<TestCollectionNonGeneric>(json);
Assert.AreEqual(3, l.Count);
Assert.AreEqual(1, l[0]);
Assert.AreEqual(2, l[1]);
Assert.AreEqual(3, l[2]);
}
#endif
public class TestDictionaryPrivateParameterized : Dictionary<string, int>
{
public TestDictionaryPrivateParameterized()
{
}
[JsonConstructor]
private TestDictionaryPrivateParameterized(IEnumerable<KeyValuePair<string, int>> bars)
: base(bars.ToDictionary(k => k.Key, k => k.Value))
{
}
}
[Test]
public void DictionaryJsonConstructorPrivateParameterized()
{
TestDictionaryPrivateParameterized c1 = new TestDictionaryPrivateParameterized();
c1.Add("zero", 0);
c1.Add("one", 1);
c1.Add("two", 2);
string json = JsonConvert.SerializeObject(c1);
TestDictionaryPrivateParameterized c2 = JsonConvert.DeserializeObject<TestDictionaryPrivateParameterized>(json);
Assert.AreEqual(3, c2.Count);
Assert.AreEqual(0, c2["zero"]);
Assert.AreEqual(1, c2["one"]);
Assert.AreEqual(2, c2["two"]);
}
public class TestDictionaryPrivate : Dictionary<string, int>
{
[JsonConstructor]
private TestDictionaryPrivate()
{
}
public static TestDictionaryPrivate Create()
{
return new TestDictionaryPrivate();
}
}
[Test]
public void DictionaryJsonConstructorPrivate()
{
TestDictionaryPrivate c1 = TestDictionaryPrivate.Create();
c1.Add("zero", 0);
c1.Add("one", 1);
c1.Add("two", 2);
string json = JsonConvert.SerializeObject(c1);
TestDictionaryPrivate c2 = JsonConvert.DeserializeObject<TestDictionaryPrivate>(json);
Assert.AreEqual(3, c2.Count);
Assert.AreEqual(0, c2["zero"]);
Assert.AreEqual(1, c2["one"]);
Assert.AreEqual(2, c2["two"]);
}
public class TestDictionaryMultipleParameters : Dictionary<string, int>
{
[JsonConstructor]
public TestDictionaryMultipleParameters(string s1, string s2)
{
}
}
[Test]
public void DictionaryJsonConstructorMultipleParameters()
{
ExceptionAssert.Throws<JsonException>(
() => JsonConvert.SerializeObject(new TestDictionaryMultipleParameters(null, null)),
"Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestDictionaryMultipleParameters' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.KeyValuePair`2[System.String,System.Int32]]'.");
}
public class TestDictionaryBadIEnumerableParameter : Dictionary<string, int>
{
[JsonConstructor]
public TestDictionaryBadIEnumerableParameter(Dictionary<string, string> l)
{
}
}
[Test]
public void DictionaryJsonConstructorBadIEnumerableParameter()
{
ExceptionAssert.Throws<JsonException>(
() => JsonConvert.SerializeObject(new TestDictionaryBadIEnumerableParameter(null)),
"Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestDictionaryBadIEnumerableParameter' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.KeyValuePair`2[System.String,System.Int32]]'.");
}
#if !(DNXCORE50 || PORTABLE)
public class TestDictionaryNonGeneric : Hashtable
{
[JsonConstructor]
public TestDictionaryNonGeneric(IDictionary d)
: base(d)
{
}
}
[Test]
public void DictionaryJsonConstructorNonGeneric()
{
string json = @"{'zero':0,'one':1,'two':2}";
TestDictionaryNonGeneric d = JsonConvert.DeserializeObject<TestDictionaryNonGeneric>(json);
Assert.AreEqual(3, d.Count);
Assert.AreEqual(0, d["zero"]);
Assert.AreEqual(1, d["one"]);
Assert.AreEqual(2, d["two"]);
}
#endif
#if !(NETFX_CORE || DNXCORE50)
public class NameValueCollectionTestClass
{
@@ -58,7 +58,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 1);
var creator = DynamicReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = DynamicReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input" };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -71,7 +71,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 2);
var creator = DynamicReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = DynamicReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input", false };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -85,7 +85,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 3);
var creator = DynamicReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = DynamicReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input", true, null };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -55,7 +55,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = TestReflectionUtils.GetConstructors(typeof(OutAndRefTestClass)).Single(c => c.GetParameters().Count() == 1);
var creator = ExpressionReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = ExpressionReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input" };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -68,7 +68,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = TestReflectionUtils.GetConstructors(typeof(OutAndRefTestClass)).Single(c => c.GetParameters().Count() == 2);
var creator = ExpressionReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = ExpressionReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input", null };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -81,7 +81,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = TestReflectionUtils.GetConstructors(typeof(OutAndRefTestClass)).Single(c => c.GetParameters().Count() == 3);
var creator = ExpressionReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = ExpressionReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input", true, null };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -54,7 +54,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = TestReflectionUtils.GetConstructors(typeof(OutAndRefTestClass)).Single(c => c.GetParameters().Count() == 1);
var creator = LateBoundReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = LateBoundReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input" };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -67,7 +67,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = TestReflectionUtils.GetConstructors(typeof(OutAndRefTestClass)).Single(c => c.GetParameters().Count() == 2);
var creator = LateBoundReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = LateBoundReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input", null };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -80,7 +80,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
ConstructorInfo constructor = TestReflectionUtils.GetConstructors(typeof(OutAndRefTestClass)).Single(c => c.GetParameters().Count() == 3);
var creator = LateBoundReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
var creator = LateBoundReflectionDelegateFactory.Instance.CreateParameterizedConstructor(constructor);
object[] args = new object[] { "Input", true, null };
OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
@@ -398,7 +398,7 @@ namespace Newtonsoft.Json.Serialization
}
else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
{
ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType);
ConstructorInfo constructor = GetParameterizedConstructor(contract.NonNullableUnderlyingType);
if (constructor != null)
{
#pragma warning disable 618
@@ -511,7 +511,7 @@ namespace Newtonsoft.Json.Serialization
Type enumerableWrapper = typeof(DictionaryEnumerator<,>).MakeGenericType(keyType, valueType);
ConstructorInfo constructors = enumerableWrapper.GetConstructors().First();
ObjectConstructor<object> createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(constructors);
ObjectConstructor<object> createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructors);
ExtensionDataGetter extensionDataGetter = o =>
{
@@ -591,7 +591,7 @@ namespace Newtonsoft.Json.Serialization
return null;
}
private ConstructorInfo GetParametrizedConstructor(Type objectType)
private ConstructorInfo GetParameterizedConstructor(Type objectType)
{
IList<ConstructorInfo> constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).ToList();
@@ -878,6 +878,31 @@ namespace Newtonsoft.Json.Serialization
contract.DictionaryKeyResolver = ResolveDictionaryKey;
ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
if (overrideConstructor != null)
{
ParameterInfo[] parameters = overrideConstructor.GetParameters();
Type expectedParameterType = (contract.DictionaryKeyType != null && contract.DictionaryValueType != null)
? typeof(IEnumerable<>).MakeGenericType(typeof(KeyValuePair<,>).MakeGenericType(contract.DictionaryKeyType, contract.DictionaryValueType))
: typeof(IDictionary);
if (parameters.Length == 0)
{
contract.HasParameterizedCreator = false;
}
else if (parameters.Length == 1 && expectedParameterType.IsAssignableFrom(parameters[0].ParameterType))
{
contract.HasParameterizedCreator = true;
}
else
{
throw new JsonException("Constructor for '{0}' must have no parameters or a single parameter that implements '{1}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, expectedParameterType));
}
contract.OverrideCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(overrideConstructor);
}
return contract;
}
@@ -891,6 +916,31 @@ namespace Newtonsoft.Json.Serialization
JsonArrayContract contract = new JsonArrayContract(objectType);
InitializeContract(contract);
ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
if (overrideConstructor != null)
{
ParameterInfo[] parameters = overrideConstructor.GetParameters();
Type expectedParameterType = (contract.CollectionItemType != null)
? typeof(IEnumerable<>).MakeGenericType(contract.CollectionItemType)
: typeof(IEnumerable);
if (parameters.Length == 0)
{
contract.HasParameterizedCreator = false;
}
else if (parameters.Length == 1 && expectedParameterType.IsAssignableFrom(parameters[0].ParameterType))
{
contract.HasParameterizedCreator = true;
}
else
{
throw new JsonException("Constructor for '{0}' must have no parameters or a single parameter that implements '{1}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, expectedParameterType));
}
contract.OverrideCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(overrideConstructor);
}
return contract;
}
@@ -934,7 +984,7 @@ namespace Newtonsoft.Json.Serialization
ConstructorInfo constructorInfo = contract.NonNullableUnderlyingType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);
if (constructorInfo != null)
{
ObjectConstructor<object> creator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(constructorInfo);
ObjectConstructor<object> creator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructorInfo);
contract.ISerializableCreator = creator;
}
@@ -67,23 +67,46 @@ namespace Newtonsoft.Json.Serialization
internal bool ShouldCreateWrapper { get; private set; }
internal bool CanDeserialize { get; private set; }
private readonly ConstructorInfo _parametrizedConstructor;
private readonly ConstructorInfo _parameterizedConstructor;
private ObjectConstructor<object> _parametrizedCreator;
internal ObjectConstructor<object> ParametrizedCreator
private ObjectConstructor<object> _parameterizedCreator;
private ObjectConstructor<object> _overrideCreator;
internal ObjectConstructor<object> ParameterizedCreator
{
get
{
if (_parametrizedCreator == null)
_parametrizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(_parametrizedConstructor);
if (_parameterizedCreator == null)
_parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor);
return _parametrizedCreator;
return _parameterizedCreator;
}
}
internal bool HasParametrizedCreator
/// <summary>
/// Gets or sets the function used to create the object. When set this function will override <see cref="JsonContract.DefaultCreator"/>.
/// </summary>
/// <value>The function used to create the object.</value>
public ObjectConstructor<object> OverrideCreator
{
get { return _parametrizedCreator != null || _parametrizedConstructor != null; }
get { return _overrideCreator; }
set
{
_overrideCreator = value;
// hacky
CanDeserialize = true;
}
}
/// <summary>
/// Gets a value indicating whether the creator has a parameter with the collection values.
/// </summary>
/// <value><c>true</c> if the creator has a parameter with the collection values; otherwise, <c>false</c>.</value>
public bool HasParameterizedCreator { get; set; }
internal bool HasParameterizedCreatorInternal
{
get { return (HasParameterizedCreator || _parameterizedCreator != null || _parameterizedConstructor != null); }
}
/// <summary>
@@ -119,7 +142,7 @@ namespace Newtonsoft.Json.Serialization
CreatedType = typeof(List<object>);
if (CollectionItemType != null)
_parametrizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyCollection<>));
canDeserialize = true;
@@ -137,7 +160,7 @@ namespace Newtonsoft.Json.Serialization
CreatedType = typeof(HashSet<>).MakeGenericType(CollectionItemType);
#endif
_parametrizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
canDeserialize = true;
ShouldCreateWrapper = true;
}
@@ -151,9 +174,9 @@ namespace Newtonsoft.Json.Serialization
CreatedType = typeof(ReadOnlyCollection<>).MakeGenericType(CollectionItemType);
_genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType);
_parametrizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, CollectionItemType);
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, CollectionItemType);
IsReadOnlyOrFixedSize = true;
canDeserialize = HasParametrizedCreator;
canDeserialize = HasParameterizedCreatorInternal;
}
#endif
else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out tempCollectionType))
@@ -163,13 +186,13 @@ namespace Newtonsoft.Json.Serialization
if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IEnumerable<>)))
CreatedType = typeof(List<>).MakeGenericType(CollectionItemType);
_parametrizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
#if !(NET35 || NET20)
if (!HasParametrizedCreator && underlyingType.Name == FSharpUtils.FSharpListTypeName)
if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpListTypeName)
{
FSharpUtils.EnsureInitialized(underlyingType.Assembly());
_parametrizedCreator = FSharpUtils.CreateSeq(CollectionItemType);
_parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType);
}
#endif
@@ -187,7 +210,7 @@ namespace Newtonsoft.Json.Serialization
IsReadOnlyOrFixedSize = true;
ShouldCreateWrapper = true;
canDeserialize = HasParametrizedCreator;
canDeserialize = HasParameterizedCreatorInternal;
}
}
else
@@ -218,7 +241,7 @@ namespace Newtonsoft.Json.Serialization
if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract(underlyingType, CollectionItemType, out immutableCreatedType, out immutableParameterizedCreator))
{
CreatedType = immutableCreatedType;
_parametrizedCreator = immutableParameterizedCreator;
_parameterizedCreator = immutableParameterizedCreator;
IsReadOnlyOrFixedSize = true;
CanDeserialize = true;
}
@@ -240,7 +263,7 @@ namespace Newtonsoft.Json.Serialization
constructorArgument = _genericCollectionDefinitionType;
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument });
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(genericWrapperConstructor);
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor);
}
return (IWrappedCollection)_genericWrapperCreator(list);
@@ -251,7 +274,10 @@ namespace Newtonsoft.Json.Serialization
if (_genericTemporaryCollectionCreator == null)
{
// multidimensional array will also have array instances in it
Type collectionItemType = (IsMultidimensionalArray) ? typeof(object) : CollectionItemType;
Type collectionItemType = (IsMultidimensionalArray || CollectionItemType == null)
? typeof(object)
: CollectionItemType;
Type temporaryListType = typeof(List<>).MakeGenericType(collectionItemType);
_genericTemporaryCollectionCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(temporaryListType);
}
@@ -105,8 +105,11 @@ namespace Newtonsoft.Json.Serialization
if (jsonContainerAttribute != null)
{
if (jsonContainerAttribute.ItemConverterType != null)
ItemConverter = JsonTypeReflector.CreateJsonConverterInstance(jsonContainerAttribute.ItemConverterType,
jsonContainerAttribute.ItemConverterParameters);
{
ItemConverter = JsonTypeReflector.CreateJsonConverterInstance(
jsonContainerAttribute.ItemConverterType,
jsonContainerAttribute.ItemConverterParameters);
}
ItemIsReference = jsonContainerAttribute._itemIsReference;
ItemReferenceLoopHandling = jsonContainerAttribute._itemReferenceLoopHandling;
@@ -81,23 +81,41 @@ namespace Newtonsoft.Json.Serialization
internal bool ShouldCreateWrapper { get; private set; }
private readonly ConstructorInfo _parametrizedConstructor;
private readonly ConstructorInfo _parameterizedConstructor;
private ObjectConstructor<object> _parametrizedCreator;
internal ObjectConstructor<object> ParametrizedCreator
private ObjectConstructor<object> _overrideCreator;
private ObjectConstructor<object> _parameterizedCreator;
internal ObjectConstructor<object> ParameterizedCreator
{
get
{
if (_parametrizedCreator == null)
_parametrizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(_parametrizedConstructor);
if (_parameterizedCreator == null)
_parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor);
return _parametrizedCreator;
return _parameterizedCreator;
}
}
internal bool HasParametrizedCreator
/// <summary>
/// Gets or sets the function used to create the object. When set this function will override <see cref="JsonContract.DefaultCreator"/>.
/// </summary>
/// <value>The function used to create the object.</value>
public ObjectConstructor<object> OverrideCreator
{
get { return _parametrizedCreator != null || _parametrizedConstructor != null; }
get { return _overrideCreator; }
set { _overrideCreator = value; }
}
/// <summary>
/// Gets a value indicating whether the creator has a parameter with the dictionary values.
/// </summary>
/// <value><c>true</c> if the creator has a parameter with the dictionary values; otherwise, <c>false</c>.</value>
public bool HasParameterizedCreator { get; set; }
internal bool HasParameterizedCreatorInternal
{
get { return (HasParameterizedCreator || _parameterizedCreator != null || _parameterizedConstructor != null); }
}
/// <summary>
@@ -146,13 +164,13 @@ namespace Newtonsoft.Json.Serialization
if (keyType != null && valueType != null)
{
_parametrizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType));
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType));
#if !(NET35 || NET20)
if (!HasParametrizedCreator && underlyingType.Name == FSharpUtils.FSharpMapTypeName)
if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName)
{
FSharpUtils.EnsureInitialized(underlyingType.Assembly());
_parametrizedCreator = FSharpUtils.CreateMap(keyType, valueType);
_parameterizedCreator = FSharpUtils.CreateMap(keyType, valueType);
}
#endif
}
@@ -182,7 +200,7 @@ namespace Newtonsoft.Json.Serialization
if (ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract(underlyingType, DictionaryKeyType, DictionaryValueType, out immutableCreatedType, out immutableParameterizedCreator))
{
CreatedType = immutableCreatedType;
_parametrizedCreator = immutableParameterizedCreator;
_parameterizedCreator = immutableParameterizedCreator;
IsReadOnlyOrFixedSize = true;
}
#endif
@@ -195,7 +213,7 @@ namespace Newtonsoft.Json.Serialization
_genericWrapperType = typeof(DictionaryWrapper<,>).MakeGenericType(DictionaryKeyType, DictionaryValueType);
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(genericWrapperConstructor);
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor);
}
return (IWrappedDictionary)_genericWrapperCreator(dictionary);
@@ -205,7 +223,7 @@ namespace Newtonsoft.Json.Serialization
{
if (_genericTemporaryDictionaryCreator == null)
{
Type temporaryDictionaryType = typeof(Dictionary<,>).MakeGenericType(DictionaryKeyType, DictionaryValueType);
Type temporaryDictionaryType = typeof(Dictionary<,>).MakeGenericType(DictionaryKeyType ?? typeof(object), DictionaryValueType ?? typeof(object));
_genericTemporaryDictionaryCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(temporaryDictionaryType);
}
@@ -69,7 +69,18 @@ namespace Newtonsoft.Json.Serialization
/// <summary>
/// Gets a collection of <see cref="JsonProperty"/> instances that define the parameters used with <see cref="OverrideCreator"/>.
/// </summary>
public JsonPropertyCollection CreatorParameters { get; private set; }
public JsonPropertyCollection CreatorParameters
{
get
{
if (_creatorParameters == null)
{
_creatorParameters = new JsonPropertyCollection(UnderlyingType);
}
return _creatorParameters;
}
}
/// <summary>
/// Gets or sets the override constructor used to create the object.
@@ -84,7 +95,7 @@ namespace Newtonsoft.Json.Serialization
set
{
_overrideConstructor = value;
_overrideCreator = (value != null) ? JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(value) : null;
_overrideCreator = (value != null) ? JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(value) : null;
}
}
@@ -99,7 +110,7 @@ namespace Newtonsoft.Json.Serialization
set
{
_parametrizedConstructor = value;
_parametrizedCreator = (value != null) ? JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(value) : null;
_parameterizedCreator = (value != null) ? JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(value) : null;
}
}
@@ -118,9 +129,9 @@ namespace Newtonsoft.Json.Serialization
}
}
internal ObjectConstructor<object> ParametrizedCreator
internal ObjectConstructor<object> ParameterizedCreator
{
get { return _parametrizedCreator; }
get { return _parameterizedCreator; }
}
/// <summary>
@@ -137,7 +148,8 @@ namespace Newtonsoft.Json.Serialization
private ConstructorInfo _parametrizedConstructor;
private ConstructorInfo _overrideConstructor;
private ObjectConstructor<object> _overrideCreator;
private ObjectConstructor<object> _parametrizedCreator;
private ObjectConstructor<object> _parameterizedCreator;
private JsonPropertyCollection _creatorParameters;
internal bool HasRequiredOrDefaultValueProperties
{
@@ -178,7 +190,6 @@ namespace Newtonsoft.Json.Serialization
ContractType = JsonContractType.Object;
Properties = new JsonPropertyCollection(UnderlyingType);
CreatorParameters = new JsonPropertyCollection(UnderlyingType);
}
#if !(DOTNET || PORTABLE40 || PORTABLE)
@@ -484,7 +484,7 @@ namespace Newtonsoft.Json.Serialization
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)
if (!dictionaryContract.HasParameterizedCreatorInternal)
throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size dictionary: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
}
@@ -492,7 +492,9 @@ namespace Newtonsoft.Json.Serialization
if (createdFromNonDefaultCreator)
{
return dictionaryContract.ParametrizedCreator(dictionary);
ObjectConstructor<object> creator = dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator;
return creator(dictionary);
}
else if (dictionary is IWrappedDictionary)
{
@@ -786,14 +788,18 @@ namespace Newtonsoft.Json.Serialization
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)
if (!arrayContract.HasParameterizedCreatorInternal && !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)
{
@@ -809,8 +815,9 @@ namespace Newtonsoft.Json.Serialization
}
else
{
// call constructor that takes IEnumerable<T>
return arrayContract.ParametrizedCreator(list);
ObjectConstructor<object> creator = arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator;
return creator(list);
}
}
else if (list is IWrappedCollection)
@@ -823,7 +830,9 @@ namespace Newtonsoft.Json.Serialization
else
{
if (!arrayContract.CanDeserialize)
{
throw JsonSerializationException.Create(reader, "Cannot populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.CreatedType));
}
value = PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(existingValue) : (IList)existingValue, reader, arrayContract, member, id);
}
@@ -1037,15 +1046,32 @@ namespace Newtonsoft.Json.Serialization
{
// some types like non-generic IEnumerable can be serialized but not deserialized
if (!contract.CanDeserialize)
{
throw JsonSerializationException.Create(reader, "Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.CreatedType));
}
if (contract.IsReadOnlyOrFixedSize)
if (contract.OverrideCreator != null)
{
if (contract.HasParameterizedCreator)
{
createdFromNonDefaultCreator = true;
return contract.CreateTemporaryCollection();
}
else
{
createdFromNonDefaultCreator = false;
return (IList)contract.OverrideCreator();
}
}
else if (contract.IsReadOnlyOrFixedSize)
{
createdFromNonDefaultCreator = true;
IList list = contract.CreateTemporaryCollection();
if (contract.ShouldCreateWrapper)
{
list = contract.CreateWrapper(list);
}
return list;
}
@@ -1054,12 +1080,14 @@ namespace Newtonsoft.Json.Serialization
object list = contract.DefaultCreator();
if (contract.ShouldCreateWrapper)
{
list = contract.CreateWrapper(list);
}
createdFromNonDefaultCreator = false;
return (IList)list;
}
else if (contract.HasParametrizedCreator)
else if (contract.HasParameterizedCreatorInternal)
{
createdFromNonDefaultCreator = true;
return contract.CreateTemporaryCollection();
@@ -1075,7 +1103,20 @@ namespace Newtonsoft.Json.Serialization
private IDictionary CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract, out bool createdFromNonDefaultCreator)
{
if (contract.IsReadOnlyOrFixedSize)
if (contract.OverrideCreator != null)
{
if (contract.HasParameterizedCreator)
{
createdFromNonDefaultCreator = true;
return contract.CreateTemporaryDictionary();
}
else
{
createdFromNonDefaultCreator = false;
return (IDictionary)contract.OverrideCreator();
}
}
else if (contract.IsReadOnlyOrFixedSize)
{
createdFromNonDefaultCreator = true;
return contract.CreateTemporaryDictionary();
@@ -1090,7 +1131,7 @@ namespace Newtonsoft.Json.Serialization
createdFromNonDefaultCreator = false;
return (IDictionary)dictionary;
}
else if (contract.HasParametrizedCreator)
else if (contract.HasParameterizedCreatorInternal)
{
createdFromNonDefaultCreator = true;
return contract.CreateTemporaryDictionary();
@@ -1937,7 +1978,7 @@ namespace Newtonsoft.Json.Serialization
newObject = objectContract.OverrideCreator(new object[0]);
}
else if (objectContract.DefaultCreator != null &&
(!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedCreator == null))
(!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParameterizedCreator == null))
{
// use the default constructor if it is...
// public
@@ -1945,10 +1986,10 @@ namespace Newtonsoft.Json.Serialization
// non-public and there is no other creator
newObject = objectContract.DefaultCreator();
}
else if (objectContract.ParametrizedCreator != null)
else if (objectContract.ParameterizedCreator != null)
{
createdFromNonDefaultCreator = true;
return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.ParametrizedCreator, id);
return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.ParameterizedCreator, id);
}
if (newObject == null)
@@ -193,7 +193,7 @@ namespace Newtonsoft.Json.Serialization
if (null != parameterizedConstructorInfo)
{
parameterizedConstructor = ReflectionDelegateFactory.CreateParametrizedConstructor(parameterizedConstructorInfo);
parameterizedConstructor = ReflectionDelegateFactory.CreateParameterizedConstructor(parameterizedConstructorInfo);
return (JsonConverter)parameterizedConstructor(parameters);
}
else
@@ -124,7 +124,9 @@ namespace Newtonsoft.Json.Utilities
if (match == null)
{
if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
{
match = constructor;
}
}
}
}
@@ -49,7 +49,7 @@ namespace Newtonsoft.Json.Utilities
return dynamicMethod;
}
public override ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method)
public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object[]) }, method.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
@@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Utilities
get { return _instance; }
}
public override ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method)
public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, "method");
+2 -2
View File
@@ -144,7 +144,7 @@ namespace Newtonsoft.Json.Utilities
{
MethodInfo seqType = _ofSeq.MakeGenericMethod(t);
return JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(seqType);
return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType);
}
public static ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
@@ -160,7 +160,7 @@ namespace Newtonsoft.Json.Utilities
{
Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue));
ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable<Tuple<TKey, TValue>>) });
ObjectConstructor<object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(ctor);
ObjectConstructor<object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(ctor);
ObjectConstructor<object> creator = args =>
{
@@ -122,7 +122,7 @@ namespace Newtonsoft.Json.Utilities
{
createdType = createdTypeDefinition.MakeGenericType(collectionItemType);
MethodInfo method = mb.MakeGenericMethod(collectionItemType);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(method);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(method);
return true;
}
}
@@ -159,7 +159,7 @@ namespace Newtonsoft.Json.Utilities
{
createdType = createdTypeDefinition.MakeGenericType(keyItemType, valueItemType);
MethodInfo method = mb.MakeGenericMethod(keyItemType, valueItemType);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(method);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(method);
return true;
}
}
@@ -42,7 +42,7 @@ namespace Newtonsoft.Json.Utilities
get { return _instance; }
}
public override ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method)
public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, "method");
@@ -63,7 +63,7 @@ namespace Newtonsoft.Json.Utilities
}
public abstract MethodCall<T, object> CreateMethodCall<T>(MethodBase method);
public abstract ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method);
public abstract ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method);
public abstract Func<T> CreateDefaultConstructor<T>(Type type);
public abstract Func<T, object> CreateGet<T>(PropertyInfo propertyInfo);
public abstract Func<T, object> CreateGet<T>(FieldInfo fieldInfo);
@@ -84,7 +84,7 @@ namespace Newtonsoft.Json.Utilities
if (creator != null)
{
d.Creator = delegateFactory.CreateParametrizedConstructor(creator);
d.Creator = delegateFactory.CreateParameterizedConstructor(creator);
}
else
{