diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ShouldSerializeTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ShouldSerializeTests.cs index b24475bb..bb23115c 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ShouldSerializeTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ShouldSerializeTests.cs @@ -27,7 +27,14 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +#if NET20 +using Newtonsoft.Json.Utilities.LinqBridge; +#else +using System.Linq; +#endif +using System.Reflection; using System.Text; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; #if NETFX_CORE using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; @@ -386,6 +393,45 @@ namespace Newtonsoft.Json.Tests.Serialization }", json); } + [Test] + public void ShouldDeserialize_True() + { + string json = @"{'HasName':true,'Name':'Name!'}"; + + MemoryTraceWriter traceWriter = new MemoryTraceWriter(); + ShouldDeserializeTestClass c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings + { + ContractResolver = ShouldDeserializeContractResolver.Instance, + TraceWriter = traceWriter + }); + + Assert.AreEqual(null, c.ExtensionData); + Assert.AreEqual(true, c.HasName); + Assert.AreEqual("Name!", c.Name); + + Assert.IsTrue(traceWriter.GetTraceMessages().Any(m => m.EndsWith("Verbose ShouldDeserialize result for property 'Name' on Newtonsoft.Json.Tests.Serialization.ShouldDeserializeTestClass: True. Path 'Name'."))); + } + + [Test] + public void ShouldDeserialize_False() + { + string json = @"{'HasName':false,'Name':'Name!'}"; + + MemoryTraceWriter traceWriter = new MemoryTraceWriter(); + ShouldDeserializeTestClass c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings + { + ContractResolver = ShouldDeserializeContractResolver.Instance, + TraceWriter = traceWriter + }); + + Assert.AreEqual(1, c.ExtensionData.Count); + Assert.AreEqual("Name!", (string)c.ExtensionData["Name"]); + Assert.AreEqual(false, c.HasName); + Assert.AreEqual(null, c.Name); + + Assert.IsTrue(traceWriter.GetTraceMessages().Any(m => m.EndsWith("Verbose ShouldDeserialize result for property 'Name' on Newtonsoft.Json.Tests.Serialization.ShouldDeserializeTestClass: False. Path 'Name'."))); + } + public class Employee { public string Name { get; set; } @@ -588,4 +634,39 @@ namespace Newtonsoft.Json.Tests.Serialization return (name != null); } } + + public class ShouldDeserializeContractResolver : DefaultContractResolver + { + public static new readonly ShouldDeserializeContractResolver Instance = new ShouldDeserializeContractResolver(); + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + MethodInfo shouldDeserializeMethodInfo = member.DeclaringType.GetMethod("ShouldDeserialize" + member.Name); + + if (shouldDeserializeMethodInfo != null) + { + property.ShouldDeserialize = o => + { + return (bool)shouldDeserializeMethodInfo.Invoke(o, null); + }; + } + + return property; + } + } + + public class ShouldDeserializeTestClass + { + [JsonExtensionData] + public IDictionary ExtensionData { get; set; } + public bool HasName { get; set; } + public string Name { get; set; } + + public bool ShouldDeserializeName() + { + return HasName; + } + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonProperty.cs b/Src/Newtonsoft.Json/Serialization/JsonProperty.cs index 45c5e38d..3b7bbe68 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonProperty.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonProperty.cs @@ -236,6 +236,12 @@ namespace Newtonsoft.Json.Serialization /// A predicate used to determine whether the property should be serialize. public Predicate ShouldSerialize { get; set; } + /// + /// Gets or sets a predicate used to determine whether the property should be deserialized. + /// + /// A predicate used to determine whether the property should be deserialized. + public Predicate ShouldDeserialize { get; set; } + /// /// Gets or sets a predicate used to determine whether the property should be serialized. /// diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 28124a7e..9859c9bc 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -2051,6 +2051,15 @@ namespace Newtonsoft.Json.Serialization continue; } + if (!ShouldDeserialize(reader, property, newObject)) + { + if (!reader.Read()) + break; + + SetExtensionData(contract, member, reader, memberName, newObject); + continue; + } + if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); @@ -2097,6 +2106,21 @@ namespace Newtonsoft.Json.Serialization return newObject; } + private bool ShouldDeserialize(JsonReader reader, JsonProperty property, object target) + { + if (property.ShouldDeserialize == null) + return true; + + bool shouldDeserialize = property.ShouldDeserialize(target); + + if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + { + TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, reader.Path, "ShouldDeserialize result for property '{0}' on {1}: {2}".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, property.DeclaringType, shouldDeserialize)), null); + } + + return shouldDeserialize; + } + private bool CheckPropertyName(JsonReader reader, string memberName) { if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.ReadAhead)