From b8400f8fb3c5627f920a7b4019c48c072deb47d6 Mon Sep 17 00:00:00 2001 From: MiNG Date: Wed, 15 Apr 2015 16:34:45 +0800 Subject: [PATCH 1/2] New features: Optional handles the "null" and "undefined" value for JObject.Merge() by setting MergeObjectHandling flag in JsonMergeSettings. --- Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs | 52 +++++++++++++++++++ Src/Newtonsoft.Json/Linq/JObject.cs | 24 ++++++++- Src/Newtonsoft.Json/Linq/JsonMergeSettings.cs | 18 +++++++ .../Linq/MergeObjectHandling.cs | 31 +++++++++++ Src/Newtonsoft.Json/Newtonsoft.Json.csproj | 1 + 5 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 Src/Newtonsoft.Json/Linq/MergeObjectHandling.cs diff --git a/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs b/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs index add425d3..025110d2 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs @@ -569,5 +569,57 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual("name1", p.Name); Assert.AreEqual(0, p.Count); } + + [Test] + public void MergeNullValue() + { + var source = new JObject + { + {"Property1", "value"}, + {"Property2", new JObject()}, + {"Property3", JValue.CreateNull()}, + {"Property4", JValue.CreateUndefined()}, + }; + + var patch = JObject.Parse("{Property1:null, Property2:null, Property3:null, Property4:null}"); + + source.Merge(patch, new JsonMergeSettings + { + MergetObjectHandling = MergeObjectHandling.Null, + }); + + Assert.IsNotNull(source["Property1"]); + Assert.AreEqual(JTokenType.Null, source["Property1"].Type); + Assert.IsNotNull(source["Property2"]); + Assert.AreEqual(JTokenType.Null, source["Property2"].Type); + Assert.IsNotNull(source["Property3"]); + Assert.AreEqual(JTokenType.Null, source["Property3"].Type); + Assert.IsNotNull(source["Property4"]); + Assert.AreEqual(JTokenType.Null, source["Property4"].Type); + } + + [Test] + public void MergeUndefinedlValue() + { + var source = new JObject + { + {"Property1", "value"}, + {"Property2", new JObject()}, + {"Property3", JValue.CreateNull()}, + {"Property4", JValue.CreateUndefined()}, + }; + + var patch = JObject.Parse("{Property1:undefined, Property2:undefined, Property3:undefined, Property4:undefined}"); + + source.Merge(patch, new JsonMergeSettings + { + MergetObjectHandling = MergeObjectHandling.Undefined, + }); + + Assert.IsNull(source.Property("Property1")); + Assert.IsNull(source.Property("Property2")); + Assert.IsNull(source.Property("Property3")); + Assert.IsNull(source.Property("Property4")); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index 0ef4b0ea..c9bfec54 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -171,11 +171,31 @@ namespace Newtonsoft.Json.Linq } else if (contentItem.Value != null) { + if (settings != null) + { + if (contentItem.Value.Type == JTokenType.Null) + { + if ((settings.MergetObjectHandling & MergeObjectHandling.Null) != 0) + { + existingProperty.Value = contentItem.Value; + } + continue; + } + + if (contentItem.Value.Type == JTokenType.Undefined) + { + if ((settings.MergetObjectHandling & MergeObjectHandling.Undefined) != 0) + { + existingProperty.Remove(); + } + continue; + } + } + JContainer existingContainer = existingProperty.Value as JContainer; if (existingContainer == null) { - if (contentItem.Value.Type != JTokenType.Null) - existingProperty.Value = contentItem.Value; + existingProperty.Value = contentItem.Value; } else if (existingContainer.Type != contentItem.Value.Type) { diff --git a/Src/Newtonsoft.Json/Linq/JsonMergeSettings.cs b/Src/Newtonsoft.Json/Linq/JsonMergeSettings.cs index 3f33c6a3..ac595c29 100644 --- a/Src/Newtonsoft.Json/Linq/JsonMergeSettings.cs +++ b/Src/Newtonsoft.Json/Linq/JsonMergeSettings.cs @@ -9,6 +9,8 @@ namespace Newtonsoft.Json.Linq { private MergeArrayHandling _mergeArrayHandling; + private MergeObjectHandling _mergeObjectHandling; + /// /// Gets or sets the method used when merging JSON arrays. /// @@ -24,5 +26,21 @@ namespace Newtonsoft.Json.Linq _mergeArrayHandling = value; } } + + /// + /// Gets or sets the method used when merging JSON objects. + /// + /// The method used when merging JSON objects. + public MergeObjectHandling MergetObjectHandling + { + get { return _mergeObjectHandling; } + set + { + if ((value | MergeObjectHandling.All) != MergeObjectHandling.All) + throw new ArgumentOutOfRangeException("value"); + + _mergeObjectHandling = value; + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/MergeObjectHandling.cs b/Src/Newtonsoft.Json/Linq/MergeObjectHandling.cs new file mode 100644 index 00000000..0a05165d --- /dev/null +++ b/Src/Newtonsoft.Json/Linq/MergeObjectHandling.cs @@ -0,0 +1,31 @@ +using System; + +namespace Newtonsoft.Json.Linq +{ + /// + /// Specifies how JSON objects are merged together. + /// + [Flags] + public enum MergeObjectHandling + { + /// + /// Uses default behaviour (ignore null and undefined) to merge the objects. + /// + None = 0, + + /// + /// The target object's null value will be set to the source object. + /// + Null = 1, + + /// + /// The target objects's explicit undefined value will remove the source object's property. + /// + Undefined = 2, + + /// + /// Merge objects uses and policy. + /// + All = Null | Undefined, + } +} diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 63db3c2d..6921bc6d 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -136,6 +136,7 @@ + From ad2fa99c72341a7b9223a4e7302fa9641e97eb65 Mon Sep 17 00:00:00 2001 From: MiNG Date: Thu, 16 Apr 2015 14:30:34 +0800 Subject: [PATCH 2/2] Fixes missing MergeObjectHandling in the reset platform. --- Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj | 1 + Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj | 1 + Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj | 1 + Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj | 1 + Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj | 1 + 5 files changed, 5 insertions(+) diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index 8ccf90ca..f34109b4 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -121,6 +121,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj index c56ce389..56b4e907 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj @@ -134,6 +134,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj index a75d290d..d014d036 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj @@ -134,6 +134,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj index b3c798b9..e44c65d3 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj @@ -132,6 +132,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj index 6a8fb1e0..283e0b14 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj @@ -137,6 +137,7 @@ +