-More object creation refactoring
This commit is contained in:
@@ -75,4 +75,4 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17302")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17307")]
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
#if !NETFX_CORE
|
||||
@@ -66,7 +67,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[Test]
|
||||
public void FailWithPrivateConstructorPlusParametizedAndDefault()
|
||||
{
|
||||
ExceptionAssert.Throws<TargetInvocationException>(
|
||||
ExceptionAssert.Throws<Exception>(
|
||||
null,
|
||||
() =>
|
||||
{
|
||||
|
||||
@@ -150,6 +150,74 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
Assert.IsFalse(contract.Properties.Any(c => c.PropertyName == "InvariantInfo"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParametrizedCreator()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonObjectContract)resolver.ResolveContract(typeof(PublicParametizedConstructorWithPropertyNameConflictWithAttribute));
|
||||
|
||||
Assert.IsNull(contract.DefaultCreator);
|
||||
Assert.IsNotNull(contract.ParametrizedCreator);
|
||||
#pragma warning disable 618
|
||||
Assert.AreEqual(contract.ParametrizedConstructor, typeof(PublicParametizedConstructorWithPropertyNameConflictWithAttribute).GetConstructor(new[] { typeof(string) }));
|
||||
#pragma warning restore 618
|
||||
Assert.AreEqual(1, contract.CreatorParameters.Count);
|
||||
Assert.AreEqual("name", contract.CreatorParameters[0].PropertyName);
|
||||
|
||||
#pragma warning disable 618
|
||||
contract.ParametrizedConstructor = null;
|
||||
#pragma warning restore 618
|
||||
Assert.IsNull(contract.ParametrizedCreator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OverrideCreator()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonObjectContract)resolver.ResolveContract(typeof(MultipleParamatrizedConstructorsJsonConstructor));
|
||||
|
||||
Assert.IsNull(contract.DefaultCreator);
|
||||
Assert.IsNotNull(contract.OverrideCreator);
|
||||
#pragma warning disable 618
|
||||
Assert.AreEqual(contract.OverrideConstructor, typeof(MultipleParamatrizedConstructorsJsonConstructor).GetConstructor(new[] { typeof(string), typeof(int) }));
|
||||
#pragma warning restore 618
|
||||
Assert.AreEqual(2, contract.CreatorParameters.Count);
|
||||
Assert.AreEqual("Value", contract.CreatorParameters[0].PropertyName);
|
||||
Assert.AreEqual("Age", contract.CreatorParameters[1].PropertyName);
|
||||
|
||||
#pragma warning disable 618
|
||||
contract.OverrideConstructor = null;
|
||||
#pragma warning restore 618
|
||||
Assert.IsNull(contract.OverrideCreator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CustomOverrideCreator()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonObjectContract)resolver.ResolveContract(typeof(MultipleParamatrizedConstructorsJsonConstructor));
|
||||
|
||||
bool ensureCustomCreatorCalled = false;
|
||||
|
||||
contract.OverrideCreator = args =>
|
||||
{
|
||||
ensureCustomCreatorCalled = true;
|
||||
return new MultipleParamatrizedConstructorsJsonConstructor((string) args[0], (int) args[1]);
|
||||
};
|
||||
#pragma warning disable 618
|
||||
Assert.IsNull(contract.OverrideConstructor);
|
||||
#pragma warning restore 618
|
||||
|
||||
var o = JsonConvert.DeserializeObject<MultipleParamatrizedConstructorsJsonConstructor>("{Value:'value!', Age:1}", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
});
|
||||
|
||||
Assert.AreEqual("value!", o.Value);
|
||||
Assert.AreEqual(1, o.Age);
|
||||
Assert.IsTrue(ensureCustomCreatorCalled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeInterface()
|
||||
{
|
||||
|
||||
@@ -4952,27 +4952,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
Assert.IsTrue(deserializedResponse.Data.DeepEquals(response.Data));
|
||||
}
|
||||
|
||||
public abstract class Test<T>
|
||||
{
|
||||
public abstract T Value { get; set; }
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class DecimalTest : Test<decimal>
|
||||
{
|
||||
protected DecimalTest()
|
||||
{
|
||||
}
|
||||
|
||||
public DecimalTest(decimal val)
|
||||
{
|
||||
Value = val;
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
public override decimal Value { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeMinValueDecimal()
|
||||
{
|
||||
@@ -4983,24 +4962,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
Assert.AreEqual(decimal.MinValue, obj.Value);
|
||||
}
|
||||
|
||||
public class NonPublicConstructorWithJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public string Constructor { get; private set; }
|
||||
|
||||
[JsonConstructor]
|
||||
private NonPublicConstructorWithJsonConstructor()
|
||||
{
|
||||
Constructor = "NonPublic";
|
||||
}
|
||||
|
||||
public NonPublicConstructorWithJsonConstructor(string value)
|
||||
{
|
||||
Value = value;
|
||||
Constructor = "Public Paramatized";
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NonPublicConstructorWithJsonConstructorTest()
|
||||
{
|
||||
@@ -5008,24 +4969,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
Assert.AreEqual("NonPublic", c.Constructor);
|
||||
}
|
||||
|
||||
public class PublicConstructorOverridenByJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public string Constructor { get; private set; }
|
||||
|
||||
public PublicConstructorOverridenByJsonConstructor()
|
||||
{
|
||||
Constructor = "NonPublic";
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public PublicConstructorOverridenByJsonConstructor(string value)
|
||||
{
|
||||
Value = value;
|
||||
Constructor = "Public Paramatized";
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PublicConstructorOverridenByJsonConstructorTest()
|
||||
{
|
||||
@@ -5034,27 +4977,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
Assert.AreEqual("value!", c.Value);
|
||||
}
|
||||
|
||||
public class MultipleParamatrizedConstructorsJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public int Age { get; private set; }
|
||||
public string Constructor { get; private set; }
|
||||
|
||||
public MultipleParamatrizedConstructorsJsonConstructor(string value)
|
||||
{
|
||||
Value = value;
|
||||
Constructor = "Public Paramatized 1";
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public MultipleParamatrizedConstructorsJsonConstructor(string value, int age)
|
||||
{
|
||||
Value = value;
|
||||
Age = age;
|
||||
Constructor = "Public Paramatized 2";
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MultipleParamatrizedConstructorsJsonConstructorTest()
|
||||
{
|
||||
@@ -5064,11 +4986,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
Assert.AreEqual(1, c.Age);
|
||||
}
|
||||
|
||||
public class EnumerableClass
|
||||
{
|
||||
public IEnumerable<string> Enumerable { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeEnumerable()
|
||||
{
|
||||
@@ -5094,18 +5011,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
Assert.AreEqual("Three", c2.Enumerable.ElementAt(2));
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class ItemBase
|
||||
{
|
||||
[JsonProperty]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class ComplexItem : ItemBase
|
||||
{
|
||||
public Stream Source { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeAttributesOnBase()
|
||||
{
|
||||
@@ -5118,14 +5023,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
}", json);
|
||||
}
|
||||
|
||||
public class DeserializeStringConvert
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public double Height { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeStringEnglish()
|
||||
{
|
||||
@@ -7961,4 +7858,107 @@ Parameter name: value",
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public abstract class Test<T>
|
||||
{
|
||||
public abstract T Value { get; set; }
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class DecimalTest : Test<decimal>
|
||||
{
|
||||
protected DecimalTest()
|
||||
{
|
||||
}
|
||||
|
||||
public DecimalTest(decimal val)
|
||||
{
|
||||
Value = val;
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
public override decimal Value { get; set; }
|
||||
}
|
||||
|
||||
public class NonPublicConstructorWithJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public string Constructor { get; private set; }
|
||||
|
||||
[JsonConstructor]
|
||||
private NonPublicConstructorWithJsonConstructor()
|
||||
{
|
||||
Constructor = "NonPublic";
|
||||
}
|
||||
|
||||
public NonPublicConstructorWithJsonConstructor(string value)
|
||||
{
|
||||
Value = value;
|
||||
Constructor = "Public Paramatized";
|
||||
}
|
||||
}
|
||||
|
||||
public class PublicConstructorOverridenByJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public string Constructor { get; private set; }
|
||||
|
||||
public PublicConstructorOverridenByJsonConstructor()
|
||||
{
|
||||
Constructor = "NonPublic";
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public PublicConstructorOverridenByJsonConstructor(string value)
|
||||
{
|
||||
Value = value;
|
||||
Constructor = "Public Paramatized";
|
||||
}
|
||||
}
|
||||
|
||||
public class MultipleParamatrizedConstructorsJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public int Age { get; private set; }
|
||||
public string Constructor { get; private set; }
|
||||
|
||||
public MultipleParamatrizedConstructorsJsonConstructor(string value)
|
||||
{
|
||||
Value = value;
|
||||
Constructor = "Public Paramatized 1";
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public MultipleParamatrizedConstructorsJsonConstructor(string value, int age)
|
||||
{
|
||||
Value = value;
|
||||
Age = age;
|
||||
Constructor = "Public Paramatized 2";
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumerableClass
|
||||
{
|
||||
public IEnumerable<string> Enumerable { get; set; }
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class ItemBase
|
||||
{
|
||||
[JsonProperty]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class ComplexItem : ItemBase
|
||||
{
|
||||
public Stream Source { get; set; }
|
||||
}
|
||||
|
||||
public class DeserializeStringConvert
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public double Height { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -279,7 +279,7 @@ Newtonsoft.Json Error: 0 : Error!
|
||||
Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Finished deserializing System.Collections.Generic.IList`1[System.Int32]. Path 'IntList'"));
|
||||
Assert.AreEqual("Started deserializing System.String[]. Path 'StringArray', line 6, position 19.", traceWriter.TraceRecords[3].Message);
|
||||
Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.String[]. Path 'StringArray'"));
|
||||
Assert.AreEqual("Deserializing System.Version using a non-default constructor 'Void .ctor(Int32, Int32, Int32, Int32)'. Path 'Version.Major', line 11, position 13.", traceWriter.TraceRecords[5].Message);
|
||||
Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path 'Version.Major', line 11, position 13.", traceWriter.TraceRecords[5].Message);
|
||||
Assert.IsTrue(traceWriter.TraceRecords[6].Message.StartsWith("Started deserializing System.Version. Path 'Version'"));
|
||||
Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Finished deserializing System.Version. Path 'Version'"));
|
||||
Assert.AreEqual("Started deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary.1', line 19, position 9.", traceWriter.TraceRecords[8].Message);
|
||||
@@ -533,7 +533,7 @@ Newtonsoft.Json Error: 0 : Error!
|
||||
Assert.AreEqual("Started deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0].key!', line 6, position 14.", traceWriter.TraceRecords[3].Message);
|
||||
Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0]'"));
|
||||
Assert.AreEqual("Resolved type 'System.Version, mscorlib' to System.Version. Path '$values[1].$type', line 9, position 42.", traceWriter.TraceRecords[5].Message);
|
||||
Assert.AreEqual("Deserializing System.Version using a custom method 'Void .ctor(Int32, Int32, Int32, Int32)'. Path '$values[1].Major', line 10, position 15.", traceWriter.TraceRecords[6].Message);
|
||||
Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path '$values[1].Major', line 10, position 15.", traceWriter.TraceRecords[6].Message);
|
||||
Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Started deserializing System.Version. Path '$values[1]'"));
|
||||
Assert.IsTrue(traceWriter.TraceRecords[8].Message.StartsWith("Finished deserializing System.Version. Path '$values[1]'"));
|
||||
Assert.IsTrue(traceWriter.TraceRecords[9].Message.StartsWith("Finished deserializing System.Collections.Generic.List`1[System.Object]. Path '$values'"));
|
||||
@@ -610,12 +610,33 @@ Newtonsoft.Json Error: 0 : Error!
|
||||
TraceWriter = traceWriter
|
||||
});
|
||||
|
||||
Assert.AreEqual("Deserializing System.Version using a custom method 'Void .ctor(Int32, Int32, Int32, Int32)'. Path 'Major', line 2, position 11.", traceWriter.TraceRecords[0].Message);
|
||||
Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path 'Major', line 2, position 11.", traceWriter.TraceRecords[0].Message);
|
||||
Assert.AreEqual("Could not find member 'MissingMemberProperty' on System.Version. Path 'MissingMemberProperty', line 8, position 32.", traceWriter.TraceRecords[1].Message);
|
||||
Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Started deserializing System.Version. Path ''"));
|
||||
Assert.IsTrue(traceWriter.TraceRecords[3].Message.StartsWith("Finished deserializing System.Version. Path ''"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PublicParametizedConstructorWithPropertyNameConflictWithAttribute()
|
||||
{
|
||||
InMemoryTraceWriter traceWriter = new InMemoryTraceWriter
|
||||
{
|
||||
LevelFilter = TraceLevel.Verbose
|
||||
};
|
||||
|
||||
string json = @"{name:""1""}";
|
||||
|
||||
PublicParametizedConstructorWithPropertyNameConflictWithAttribute c = JsonConvert.DeserializeObject<PublicParametizedConstructorWithPropertyNameConflictWithAttribute>(json, new JsonSerializerSettings
|
||||
{
|
||||
TraceWriter = traceWriter
|
||||
});
|
||||
|
||||
Assert.IsNotNull(c);
|
||||
Assert.AreEqual(1, c.Name);
|
||||
|
||||
Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.PublicParametizedConstructorWithPropertyNameConflictWithAttribute using creator with parameters: name. Path 'name', line 1, position 6.", traceWriter.TraceRecords[0].Message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldSerializeTestClass()
|
||||
{
|
||||
|
||||
@@ -91,5 +91,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17302")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17307")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -380,8 +380,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
// check if a JsonConstructorAttribute has been defined and use that
|
||||
if (overrideConstructor != null)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
contract.OverrideConstructor = overrideConstructor;
|
||||
contract.ConstructorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties));
|
||||
#pragma warning restore 618
|
||||
contract.CreatorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties));
|
||||
}
|
||||
else if (contract.MemberSerialization == MemberSerialization.Fields)
|
||||
{
|
||||
@@ -397,8 +399,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType);
|
||||
if (constructor != null)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
contract.ParametrizedConstructor = constructor;
|
||||
contract.ConstructorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties));
|
||||
#pragma warning restore 618
|
||||
contract.CreatorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,16 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <summary>
|
||||
/// Gets the constructor parameters required for any non-default constructor
|
||||
/// </summary>
|
||||
public JsonPropertyCollection ConstructorParameters { get; private set; }
|
||||
[Obsolete("ConstructorParameters is obsolete. Use CreatorParameters instead.")]
|
||||
public JsonPropertyCollection ConstructorParameters
|
||||
{
|
||||
get { return CreatorParameters; }
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the override constructor used to create the object.
|
||||
@@ -68,13 +77,23 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// JsonConstructor attribute.
|
||||
/// </summary>
|
||||
/// <value>The override constructor.</value>
|
||||
[Obsolete("OverrideConstructor is obsolete. Use OverrideCreator instead.")]
|
||||
public ConstructorInfo OverrideConstructor
|
||||
{
|
||||
get { return _overrideConstructor; }
|
||||
set
|
||||
{
|
||||
_overrideConstructor = value;
|
||||
ParametrizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(value);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
MethodCall<object, object> ctor = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(value);
|
||||
_overrideCreator = args => ctor(null, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
_overrideCreator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,17 +101,44 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// Gets or sets the parametrized constructor used to create the object.
|
||||
/// </summary>
|
||||
/// <value>The parametrized constructor.</value>
|
||||
[Obsolete("ParametrizedConstructor is obsolete. Use OverrideCreator instead.")]
|
||||
public ConstructorInfo ParametrizedConstructor
|
||||
{
|
||||
get { return _parametrizedConstructor; }
|
||||
set
|
||||
{
|
||||
_parametrizedConstructor = value;
|
||||
ParametrizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(value);
|
||||
if (value != null)
|
||||
{
|
||||
MethodCall<object, object> ctor = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(value);
|
||||
_parametrizedCreator = args => ctor(null, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
_parametrizedCreator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal MethodCall<object, object> ParametrizedCreator { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the function used to create the object. When set this function will override <see cref="P:DefaultCreator"/>.
|
||||
/// This function can be called with a collection of arguments which are defined by the <see cref="CreatorParameters"/> collection.
|
||||
/// </summary>
|
||||
/// <value>The function used to create the object.</value>
|
||||
public Func<object[], object> OverrideCreator
|
||||
{
|
||||
get { return _overrideCreator; }
|
||||
set
|
||||
{
|
||||
_overrideCreator = value;
|
||||
_overrideConstructor = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal Func<object[], object> ParametrizedCreator
|
||||
{
|
||||
get { return _parametrizedCreator; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the extension data setter.
|
||||
@@ -107,6 +153,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
private bool? _hasRequiredOrDefaultValueProperties;
|
||||
private ConstructorInfo _parametrizedConstructor;
|
||||
private ConstructorInfo _overrideConstructor;
|
||||
private Func<object[], object> _overrideCreator;
|
||||
private Func<object[], object> _parametrizedCreator;
|
||||
|
||||
internal bool HasRequiredOrDefaultValueProperties
|
||||
{
|
||||
@@ -147,7 +195,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
ContractType = JsonContractType.Object;
|
||||
|
||||
Properties = new JsonPropertyCollection(UnderlyingType);
|
||||
ConstructorParameters = new JsonPropertyCollection(UnderlyingType);
|
||||
CreatorParameters = new JsonPropertyCollection(UnderlyingType);
|
||||
}
|
||||
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
|
||||
@@ -407,17 +407,17 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
case JsonContractType.Object:
|
||||
{
|
||||
bool createdFromNonDefaultConstructor = false;
|
||||
bool createdFromNonDefaultCreator = false;
|
||||
JsonObjectContract objectContract = (JsonObjectContract)contract;
|
||||
object targetObject;
|
||||
// check that if type name handling is being used that the existing value is compatible with the specified type
|
||||
if (existingValue != null && (resolvedObjectType == objectType || resolvedObjectType.IsAssignableFrom(existingValue.GetType())))
|
||||
targetObject = existingValue;
|
||||
else
|
||||
targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultConstructor);
|
||||
targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultCreator);
|
||||
|
||||
// don't populate if read from non-default constructor because the object has already been read
|
||||
if (createdFromNonDefaultConstructor)
|
||||
// don't populate if read from non-default creator because the object has already been read
|
||||
if (createdFromNonDefaultCreator)
|
||||
return targetObject;
|
||||
|
||||
return PopulateObject(targetObject, reader, objectContract, member, id);
|
||||
@@ -449,10 +449,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
if (existingValue == null)
|
||||
{
|
||||
bool createdFromNonDefaultConstructor;
|
||||
IDictionary dictionary = CreateNewDictionary(reader, dictionaryContract, out createdFromNonDefaultConstructor);
|
||||
bool createdFromNonDefaultCreator;
|
||||
IDictionary dictionary = CreateNewDictionary(reader, dictionaryContract, out createdFromNonDefaultCreator);
|
||||
|
||||
if (createdFromNonDefaultConstructor)
|
||||
if (createdFromNonDefaultCreator)
|
||||
{
|
||||
if (id != null)
|
||||
throw JsonSerializationException.Create(reader, "Cannot preserve reference to readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
@@ -469,7 +469,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
PopulateDictionary(dictionary, reader, dictionaryContract, member, id);
|
||||
|
||||
if (createdFromNonDefaultConstructor)
|
||||
if (createdFromNonDefaultCreator)
|
||||
{
|
||||
return dictionaryContract.ParametrizedCreator(null , new object[] { dictionary });
|
||||
}
|
||||
@@ -745,10 +745,10 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
|
||||
if (existingValue == null)
|
||||
{
|
||||
bool createdFromNonDefaultConstructor;
|
||||
IList list = CreateNewList(reader, arrayContract, out createdFromNonDefaultConstructor);
|
||||
bool createdFromNonDefaultCreator;
|
||||
IList list = CreateNewList(reader, arrayContract, out createdFromNonDefaultCreator);
|
||||
|
||||
if (createdFromNonDefaultConstructor)
|
||||
if (createdFromNonDefaultCreator)
|
||||
{
|
||||
if (id != null)
|
||||
throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
@@ -768,7 +768,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
else
|
||||
PopulateMultidimensionalArray(list, reader, arrayContract, member, id);
|
||||
|
||||
if (createdFromNonDefaultConstructor)
|
||||
if (createdFromNonDefaultCreator)
|
||||
{
|
||||
if (arrayContract.IsMultidimensionalArray)
|
||||
{
|
||||
@@ -1003,7 +1003,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
return true;
|
||||
}
|
||||
|
||||
private IList CreateNewList(JsonReader reader, JsonArrayContract contract, out bool createdFromNonDefaultConstructor)
|
||||
private IList CreateNewList(JsonReader reader, JsonArrayContract contract, out bool createdFromNonDefaultCreator)
|
||||
{
|
||||
// some types like non-generic IEnumerable can be serialized but not deserialized
|
||||
if (!contract.CanDeserialize)
|
||||
@@ -1011,7 +1011,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
|
||||
if (contract.IsReadOnlyOrFixedSize)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
createdFromNonDefaultCreator = true;
|
||||
IList list = contract.CreateTemporaryCollection();
|
||||
|
||||
if (contract.ShouldCreateWrapper)
|
||||
@@ -1026,12 +1026,12 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
if (contract.ShouldCreateWrapper)
|
||||
list = contract.CreateWrapper(list);
|
||||
|
||||
createdFromNonDefaultConstructor = false;
|
||||
createdFromNonDefaultCreator = false;
|
||||
return (IList)list;
|
||||
}
|
||||
else if (contract.ParametrizedCreator != null)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
createdFromNonDefaultCreator = true;
|
||||
return contract.CreateTemporaryCollection();
|
||||
}
|
||||
else
|
||||
@@ -1040,11 +1040,11 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
}
|
||||
}
|
||||
|
||||
private IDictionary CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract, out bool createdFromNonDefaultConstructor)
|
||||
private IDictionary CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract, out bool createdFromNonDefaultCreator)
|
||||
{
|
||||
if (contract.IsReadOnlyOrFixedSize)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
createdFromNonDefaultCreator = true;
|
||||
return contract.CreateTemporaryDictionary();
|
||||
}
|
||||
else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
|
||||
@@ -1054,12 +1054,12 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
if (contract.ShouldCreateWrapper)
|
||||
dictionary = contract.CreateWrapper(dictionary);
|
||||
|
||||
createdFromNonDefaultConstructor = false;
|
||||
createdFromNonDefaultCreator = false;
|
||||
return (IDictionary)dictionary;
|
||||
}
|
||||
else if (contract.ParametrizedCreator != null)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
createdFromNonDefaultCreator = true;
|
||||
return contract.CreateTemporaryDictionary();
|
||||
}
|
||||
else
|
||||
@@ -1568,9 +1568,9 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
}
|
||||
#endif
|
||||
|
||||
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, MethodCall<object, object> constructorInfo, string id)
|
||||
private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, Func<object[], object> creator, string id)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo");
|
||||
ValidationUtils.ArgumentNotNull(creator, "creator");
|
||||
|
||||
// only need to keep a track of properies presence if they are required or a value should be defaulted if missing
|
||||
Dictionary<JsonProperty, PropertyPresence> propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate))
|
||||
@@ -1581,34 +1581,34 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
|
||||
{
|
||||
string underlyingMethodName = constructorInfo.GetMethodInfo().Name;
|
||||
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using custom method '{1}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, underlyingMethodName)), null);
|
||||
string parameters = string.Join(", ", contract.CreatorParameters.Select(p => p.PropertyName).ToArray());
|
||||
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using creator with parameters: {1}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, parameters)), null);
|
||||
}
|
||||
|
||||
IDictionary<string, object> extensionData;
|
||||
IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndConstructorValues(contract, containerProperty, reader, objectType, out extensionData);
|
||||
IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType, out extensionData);
|
||||
|
||||
IDictionary<JsonProperty, object> constructorParameters = contract.ConstructorParameters.ToDictionary(p => p, p => (object)null);
|
||||
IDictionary<JsonProperty, object> creatorParameters = contract.CreatorParameters.ToDictionary(p => p, p => (object)null);
|
||||
IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
|
||||
|
||||
foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
|
||||
{
|
||||
JsonProperty matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.PropertyName, propertyValue.Key.PropertyName).Key;
|
||||
if (matchingConstructorParameter != null)
|
||||
constructorParameters[matchingConstructorParameter] = propertyValue.Value;
|
||||
JsonProperty matchingCreatorParameter = creatorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.PropertyName, propertyValue.Key.PropertyName).Key;
|
||||
if (matchingCreatorParameter != null)
|
||||
creatorParameters[matchingCreatorParameter] = propertyValue.Value;
|
||||
else
|
||||
remainingPropertyValues.Add(propertyValue);
|
||||
|
||||
if (propertiesPresence != null)
|
||||
{
|
||||
// map from constructor property to normal property
|
||||
// map from creator property to normal property
|
||||
var property = propertiesPresence.Keys.FirstOrDefault(p => p.PropertyName == propertyValue.Key.PropertyName);
|
||||
if (property != null)
|
||||
propertiesPresence[property] = (propertyValue.Value == null) ? PropertyPresence.Null : PropertyPresence.Value;
|
||||
}
|
||||
}
|
||||
|
||||
object createdObject = constructorInfo(null, constructorParameters.Values.ToArray());
|
||||
object createdObject = creator(creatorParameters.Values.ToArray());
|
||||
|
||||
if (id != null)
|
||||
AddReference(reader, id, createdObject);
|
||||
@@ -1692,7 +1692,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
return value;
|
||||
}
|
||||
|
||||
private IDictionary<JsonProperty, object> ResolvePropertyAndConstructorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType, out IDictionary<string, object> extensionData)
|
||||
private IDictionary<JsonProperty, object> ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType, out IDictionary<string, object> extensionData)
|
||||
{
|
||||
extensionData = (contract.ExtensionDataSetter != null) ? new Dictionary<string, object>() : null;
|
||||
|
||||
@@ -1707,7 +1707,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
// attempt exact case match first
|
||||
// then try match ignoring case
|
||||
JsonProperty property = contract.ConstructorParameters.GetClosestMatchProperty(memberName) ??
|
||||
JsonProperty property = contract.CreatorParameters.GetClosestMatchProperty(memberName) ??
|
||||
contract.Properties.GetClosestMatchProperty(memberName);
|
||||
|
||||
if (property != null)
|
||||
@@ -1816,42 +1816,42 @@ 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, out bool createdFromNonDefaultConstructor)
|
||||
public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultCreator)
|
||||
{
|
||||
object newObject = null;
|
||||
|
||||
if (!objectContract.IsInstantiable)
|
||||
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
|
||||
|
||||
if (objectContract.OverrideConstructor != null)
|
||||
if (objectContract.OverrideCreator != null)
|
||||
{
|
||||
if (objectContract.OverrideConstructor.GetParameters().Length > 0)
|
||||
if (objectContract.CreatorParameters.Count > 0)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedCreator, id);
|
||||
createdFromNonDefaultCreator = true;
|
||||
return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.OverrideCreator, id);
|
||||
}
|
||||
|
||||
newObject = objectContract.OverrideConstructor.Invoke(null);
|
||||
newObject = objectContract.OverrideCreator(new object[0]);
|
||||
}
|
||||
else if (objectContract.DefaultCreator != null &&
|
||||
(!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null))
|
||||
(!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedCreator == 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
|
||||
// non-public and there is no other creator
|
||||
newObject = objectContract.DefaultCreator();
|
||||
}
|
||||
else if (objectContract.ParametrizedCreator != null)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedCreator, id);
|
||||
createdFromNonDefaultCreator = true;
|
||||
return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.ParametrizedCreator, 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));
|
||||
|
||||
createdFromNonDefaultConstructor = false;
|
||||
createdFromNonDefaultCreator = false;
|
||||
return newObject;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,13 +54,26 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
for (int i = 0; i < parametersInfo.Length; i++)
|
||||
{
|
||||
Type parameterType = parametersInfo[i].ParameterType;
|
||||
|
||||
Expression indexExpression = Expression.Constant(i);
|
||||
|
||||
Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression);
|
||||
|
||||
paramAccessorExpression = EnsureCastExpression(paramAccessorExpression, parametersInfo[i].ParameterType);
|
||||
Expression argExpression;
|
||||
|
||||
argsExpression[i] = paramAccessorExpression;
|
||||
if (parameterType.IsValueType())
|
||||
{
|
||||
BinaryExpression ensureValueTypeNotNull = Expression.Coalesce(paramAccessorExpression, Expression.New(parameterType));
|
||||
|
||||
argExpression = EnsureCastExpression(ensureValueTypeNotNull, parameterType);
|
||||
}
|
||||
else
|
||||
{
|
||||
argExpression = EnsureCastExpression(paramAccessorExpression, parameterType);
|
||||
}
|
||||
|
||||
argsExpression[i] = argExpression;
|
||||
}
|
||||
|
||||
Expression callExpression;
|
||||
|
||||
Reference in New Issue
Block a user