From fcd5975cd935a6eb55b91f27e5c84f9f524eec81 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 8 Nov 2017 16:32:42 +1300 Subject: [PATCH] -Added ItemNullValueHandling to JsonObjectContract --- Src/Newtonsoft.Json/JsonObjectAttribute.cs | 4 ++-- .../Serialization/DefaultContractResolver.cs | 7 ++----- .../Serialization/JsonObjectContract.cs | 6 ++++++ .../Serialization/JsonSerializerInternalBase.cs | 10 ++++++++++ .../Serialization/JsonSerializerInternalReader.cs | 10 +++++----- .../Serialization/JsonSerializerInternalWriter.cs | 7 +++---- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Src/Newtonsoft.Json/JsonObjectAttribute.cs b/Src/Newtonsoft.Json/JsonObjectAttribute.cs index 0b532f29..82e20377 100644 --- a/Src/Newtonsoft.Json/JsonObjectAttribute.cs +++ b/Src/Newtonsoft.Json/JsonObjectAttribute.cs @@ -51,9 +51,9 @@ namespace Newtonsoft.Json } /// - /// Gets or sets the null value handling. + /// Gets or sets how the object's properties with null values are handled during serialization and deserialization. /// - /// The null value handling. + /// How the object's properties with null values are handled during serialization and deserialization. public NullValueHandling ItemNullValueHandling { get => _itemNullValueHandling ?? default(NullValueHandling); diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 44858f72..d1d4180f 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -327,6 +327,8 @@ namespace Newtonsoft.Json.Serialization if (attribute != null) { contract.ItemRequired = attribute._itemRequired; + contract.ItemNullValueHandling = attribute._itemNullValueHandling; + if (attribute.NamingStrategyType != null) { NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(attribute); @@ -1509,11 +1511,6 @@ namespace Newtonsoft.Json.Serialization #endif } - if (property.NullValueHandling == null && containerAttribute is JsonObjectAttribute objectAttribute) - { - property.NullValueHandling = objectAttribute._itemNullValueHandling; - } - if (requiredAttribute != null) { property._required = Required.Always; diff --git a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs index c80c01b2..aeb5410e 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs @@ -52,6 +52,12 @@ namespace Newtonsoft.Json.Serialization /// public Required? ItemRequired { get; set; } + /// + /// Gets or sets how the object's properties with null values are handled during serialization and deserialization. + /// + /// How the object's properties with null values are handled during serialization and deserialization. + public NullValueHandling? ItemNullValueHandling { get; set; } + /// /// Gets the object's properties. /// diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs index 1287eb39..73d8670b 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs @@ -81,6 +81,16 @@ namespace Newtonsoft.Json.Serialization } } + protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract containerContract, JsonProperty property) + { + NullValueHandling resolvedNullValueHandling = + property.NullValueHandling + ?? containerContract?.ItemNullValueHandling + ?? Serializer._nullValueHandling; + + return resolvedNullValueHandling; + } + private ErrorContext GetErrorContext(object currentObject, object member, string path, Exception error) { if (_currentErrorContext == null) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 414cfef0..20c16126 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -1012,7 +1012,7 @@ namespace Newtonsoft.Json.Serialization // otherwise also set it if CreateValue returns a new value compared to the currentValue // this could happen because of a JsonConverter against the type if ((!useExistingValue || value != currentValue) - && ShouldSetPropertyValue(property, value)) + && ShouldSetPropertyValue(property, containerContract as JsonObjectContract, value)) { property.ValueProvider.SetValue(target, value); @@ -1076,7 +1076,7 @@ namespace Newtonsoft.Json.Serialization } // test tokenType here because null might not be convertible to some types, e.g. ignoring null when applied to DateTime - if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && tokenType == JsonToken.Null) + if (tokenType == JsonToken.Null && ResolvedNullValueHandling(containerContract as JsonObjectContract, property) == NullValueHandling.Ignore) { return true; } @@ -1129,9 +1129,9 @@ namespace Newtonsoft.Json.Serialization return ((value & flag) == flag); } - private bool ShouldSetPropertyValue(JsonProperty property, object value) + private bool ShouldSetPropertyValue(JsonProperty property, JsonObjectContract contract, object value) { - if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && value == null) + if (value == null && ResolvedNullValueHandling(contract, property) == NullValueHandling.Ignore) { return false; } @@ -1992,7 +1992,7 @@ namespace Newtonsoft.Json.Serialization JsonProperty property = context.Property; object value = context.Value; - if (ShouldSetPropertyValue(property, value)) + if (ShouldSetPropertyValue(property, contract, value)) { property.ValueProvider.SetValue(createdObject, value); context.Used = true; diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index 36572dc2..51d8b2f9 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -270,10 +270,9 @@ namespace Newtonsoft.Json.Serialization return Serializer.GetReferenceResolver().IsReferenced(this, value); } - private bool ShouldWriteProperty(object memberValue, JsonProperty property) + private bool ShouldWriteProperty(object memberValue, JsonObjectContract containerContract, JsonProperty property) { - if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && - memberValue == null) + if (memberValue == null && ResolvedNullValueHandling(containerContract, property) == NullValueHandling.Ignore) { return false; } @@ -525,7 +524,7 @@ namespace Newtonsoft.Json.Serialization memberValue = property.ValueProvider.GetValue(value); memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue); - if (ShouldWriteProperty(memberValue, property)) + if (ShouldWriteProperty(memberValue, contract as JsonObjectContract, property)) { if (ShouldWriteReference(memberValue, property, memberContract, contract, member)) {