From 000407f6103f5beb064a1962186c6cb611936626 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 15 Nov 2015 21:25:47 +1300 Subject: [PATCH] -Added Required.DisallowNull --- Build/build.ps1 | 2 +- .../Serialization/JsonSerializerTest.cs | 56 +++++++++++++++++++ Src/Newtonsoft.Json/Required.cs | 7 ++- .../JsonSerializerInternalReader.cs | 8 +++ .../JsonSerializerInternalWriter.cs | 6 ++ 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index 3d887005..b2e23159 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -2,7 +2,7 @@ $zipFileName = "Json80r1.zip" $majorVersion = "8.0" $majorWithReleaseVersion = "8.0.1" - $nugetPrelease = "beta2" + $nugetPrelease = "beta3" $version = GetVersion $majorWithReleaseVersion $packageId = "Newtonsoft.Json" $signAssemblies = $false diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 82a9ae80..9b3df3ab 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -237,6 +237,22 @@ namespace Newtonsoft.Json.Tests.Serialization }, "Required property 'RequiredProperty' expects a value but got null. Path '', line 1, position 21."); } + [Test] + public void CoercedEmptyStringWithRequired_DisallowNull() + { + ExceptionAssert.Throws(() => + { + JsonConvert.DeserializeObject("{requiredProperty:''}"); + }, "Required property 'RequiredProperty' expects a non-null value. Path '', line 1, position 21."); + } + + [Test] + public void DisallowNull_NoValue() + { + Binding_DisallowNull o = JsonConvert.DeserializeObject("{}"); + Assert.IsNull(o.RequiredProperty); + } + [Test] public void CoercedEmptyStringWithRequiredConstructor() { @@ -252,6 +268,46 @@ namespace Newtonsoft.Json.Tests.Serialization public Binding RequiredProperty { get; set; } } + public class Binding_DisallowNull + { + [JsonProperty(Required = Required.DisallowNull)] + public Binding RequiredProperty { get; set; } + } + + [Test] + public void Serialize_Required_DisallowedNull() + { + ExceptionAssert.Throws(() => + { + JsonConvert.SerializeObject(new Binding_DisallowNull()); + }, "Cannot write a null value for property 'RequiredProperty'. Property requires a non-null value. Path ''."); + } + + [Test] + public void Serialize_Required_DisallowedNull_NullValueHandlingIgnore() + { + string json = JsonConvert.SerializeObject(new Binding_DisallowNull(), new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + Assert.AreEqual("{}", json); + } + + [JsonObject(ItemRequired = Required.DisallowNull)] + public class DictionaryWithNoNull + { + public string Name { get; set; } + } + + [Test] + public void Serialize_ItemRequired_DisallowedNull() + { + ExceptionAssert.Throws(() => + { + JsonConvert.SerializeObject(new DictionaryWithNoNull()); + }, "Cannot write a null value for property 'Name'. Property requires a non-null value. Path ''."); + } + public class DictionaryKeyContractResolver : DefaultContractResolver { protected override string ResolveDictionaryKey(string dictionaryKey) diff --git a/Src/Newtonsoft.Json/Required.cs b/Src/Newtonsoft.Json/Required.cs index 5e145234..47c91e13 100644 --- a/Src/Newtonsoft.Json/Required.cs +++ b/Src/Newtonsoft.Json/Required.cs @@ -43,6 +43,11 @@ namespace Newtonsoft.Json /// /// The property must be defined in JSON and cannot be a null value. /// - Always = 2 + Always = 2, + + /// + /// The property is not required but it cannot be a null value. + /// + DisallowNull = 3 } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 6ab506de..ae23f62a 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -2193,7 +2193,9 @@ namespace Newtonsoft.Json.Serialization { case PropertyPresence.None: if (resolvedRequired == Required.AllowNull || resolvedRequired == Required.Always) + { throw JsonSerializationException.Create(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); + } if (!property.Ignored) { @@ -2206,7 +2208,13 @@ namespace Newtonsoft.Json.Serialization break; case PropertyPresence.Null: if (resolvedRequired == Required.Always) + { throw JsonSerializationException.Create(reader, "Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); + } + if (resolvedRequired == Required.DisallowNull) + { + throw JsonSerializationException.Create(reader, "Required property '{0}' expects a non-null value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); + } break; } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index c011de90..c5c80296 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -490,7 +490,13 @@ namespace Newtonsoft.Json.Serialization JsonObjectContract objectContract = contract as JsonObjectContract; Required resolvedRequired = property._required ?? ((objectContract != null) ? objectContract.ItemRequired : null) ?? Required.Default; if (resolvedRequired == Required.Always) + { throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null); + } + if (resolvedRequired == Required.DisallowNull) + { + throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a non-null value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null); + } } return true;