-Fixed passing default values to constructors

This commit is contained in:
James Newton-King
2015-05-03 14:17:25 +12:00
parent fbb74d57ef
commit 7e04b45894
5 changed files with 119 additions and 6 deletions
@@ -24,7 +24,10 @@
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Tests.TestObjects;
#if NETFX_CORE
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
@@ -37,6 +40,11 @@ using Assert = Newtonsoft.Json.Tests.XUnitAssert;
#else
using NUnit.Framework;
#endif
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Tests.Serialization
{
@@ -162,5 +170,79 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.IsNotNull(c);
Assert.AreEqual(1, c.Name);
}
public class ConstructorParametersRespectDefaultValueAttributes
{
[DefaultValue("parameter1_default")]
public string Parameter1 { get; private set; }
[DefaultValue("parameter2_default")]
public string Parameter2 { get; private set; }
[DefaultValue("parameter3_default")]
public string Parameter3 { get; set; }
[DefaultValue("parameter4_default")]
public string Parameter4 { get; set; }
public ConstructorParametersRespectDefaultValueAttributes(string parameter1, string parameter2, string parameter3)
{
Parameter1 = parameter1;
Parameter2 = parameter2;
Parameter3 = parameter3;
}
}
[Test]
public void ConstructorParametersRespectDefaultValueTest_Attrbutes()
{
var testObject = JsonConvert.DeserializeObject<ConstructorParametersRespectDefaultValueAttributes>("{'Parameter2':'value!'}", new JsonSerializerSettings()
{
DefaultValueHandling = DefaultValueHandling.Populate
});
Assert.AreEqual("parameter1_default", testObject.Parameter1);
Assert.AreEqual("value!", testObject.Parameter2);
Assert.AreEqual("parameter3_default", testObject.Parameter3);
Assert.AreEqual("parameter4_default", testObject.Parameter4);
}
[Test]
public void ConstructorParametersRespectDefaultValueTest()
{
var testObject = JsonConvert.DeserializeObject<ConstructorParametersRespectDefaultValue>("{}", new JsonSerializerSettings() { ContractResolver = ConstructorParameterDefaultStringValueContractResolver.Instance });
Assert.AreEqual("Default Value", testObject.Parameter1);
Assert.AreEqual("Default Value", testObject.Parameter2);
}
public class ConstructorParametersRespectDefaultValue
{
public const string DefaultValue = "Default Value";
public string Parameter1 { get; private set; }
public string Parameter2 { get; private set; }
public ConstructorParametersRespectDefaultValue(string parameter1, string parameter2)
{
Parameter1 = parameter1;
Parameter2 = parameter2;
}
}
public class ConstructorParameterDefaultStringValueContractResolver : DefaultContractResolver
{
public static new ConstructorParameterDefaultStringValueContractResolver Instance = new ConstructorParameterDefaultStringValueContractResolver();
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
foreach (var property in properties.Where(p => p.PropertyType == typeof(string)))
{
property.DefaultValue = ConstructorParametersRespectDefaultValue.DefaultValue;
property.DefaultValueHandling = DefaultValueHandling.Populate;
}
return properties;
}
}
}
}
@@ -309,17 +309,20 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(new DateTime(2000, 12, 1, 0, 0, 0, DateTimeKind.Utc), c[2]);
Assert.AreEqual(3, errors.Count);
#if !(NET20 || NET35)
var possibleErrs = new [] {
#if !(NET20 || NET35)
"[1] - 1 - The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.",
"[1] - 1 - String was not recognized as a valid DateTime."
#else
// handle typo fix in later versions of .NET
"[1] - 1 - The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.",
"[1] - 1 - The string was not recognized as a valid DateTime. There is a unknown word starting at index 0."
#endif
};
Assert.IsTrue(possibleErrs.Any (m => m == errors[0]),
"Expected One of: " + string.Join (Environment.NewLine, possibleErrs) + Environment.NewLine + "But was: " + errors[0]);
#else
Assert.AreEqual("[1] - 1 - The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.", errors[0]);
#endif
Assert.AreEqual("[2] - 2 - Unexpected token parsing date. Expected String, got StartArray. Path '[2]', line 4, position 10.", errors[1]);
Assert.AreEqual("[4] - 4 - Cannot convert null value to System.DateTime. Path '[4]', line 8, position 13.", errors[2]);
}
+1 -1
View File
@@ -92,13 +92,13 @@
<Compile Include="JsonDictionaryAttribute.cs" />
<Compile Include="JsonException.cs" />
<Compile Include="JsonExtensionDataAttribute.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="JsonIgnoreAttribute.cs" />
<Compile Include="JsonObjectAttribute.cs" />
<Compile Include="JsonPosition.cs" />
<Compile Include="JsonPropertyAttribute.cs" />
<Compile Include="JsonReader.cs" />
<Compile Include="JsonReaderException.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="JsonSerializationException.cs" />
<Compile Include="JsonSerializer.cs" />
<Compile Include="JsonSerializerSettings.cs" />
@@ -155,7 +155,7 @@ namespace Newtonsoft.Json.Serialization
{
foreach (JsonProperty property in Properties)
{
if (property.Required != Required.Default || ((property.DefaultValueHandling & DefaultValueHandling.Populate) == DefaultValueHandling.Populate) && property.Writable)
if (property.Required != Required.Default || (property.DefaultValueHandling & DefaultValueHandling.Populate) == DefaultValueHandling.Populate)
{
_hasRequiredOrDefaultValueProperties = true;
break;
@@ -1662,6 +1662,34 @@ namespace Newtonsoft.Json.Serialization
}
}
// handle giving default values to creator parameters
// this needs to happen before the call to creator
if (propertiesPresence != null)
{
foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence)
{
JsonProperty property = propertyPresence.Key;
PropertyPresence presence = propertyPresence.Value;
if (!property.Ignored && (presence == PropertyPresence.None || presence == PropertyPresence.Null))
{
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate))
{
// have to use the name because property presence doesn't use creator properties
int i = contract.CreatorParameters.IndexOf(p => p.PropertyName == property.PropertyName);
if (i != -1)
{
creatorParameterValues[i] = EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType);
}
}
}
}
}
object createdObject = creator(creatorParameterValues);
if (id != null)