From a1f1b0aa86d72a8172a0fb5c22a73663b4f3969a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD?= Date: Fri, 19 Oct 2018 03:20:47 +0300 Subject: [PATCH] initial commit issue #931 fix --- .../JsonTextReaderTests/ReadAsyncTests.cs | 26 +++++++++++- .../JsonTextReaderTests/ReadTests.cs | 27 ++++++++++++ .../Linq/DuplicatePropertyNamesHandling.cs | 42 +++++++++++++++++++ Src/Newtonsoft.Json/Linq/JContainer.Async.cs | 4 ++ Src/Newtonsoft.Json/Linq/JContainer.cs | 4 ++ Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs | 20 +++++++++ 6 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 Src/Newtonsoft.Json/Linq/DuplicatePropertyNamesHandling.cs diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs index 8567afa1..a1356f82 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs @@ -1752,7 +1752,29 @@ third line", jsonTextReader.Value); Assert.IsTrue(reader.ReadAsInt32Async(token).IsCanceled); Assert.IsTrue(reader.ReadAsStringAsync(token).IsCanceled); } - } -} + [Test] + public async Task ThrowOnDuplicateKeysDeserializingAsync() + { + string json = @" + { + ""a"": 1, + ""b"": [ + { + ""c"": { + ""d"": 1, + ""d"": ""2"" + } + } + ] + } + "; + + JsonLoadSettings settings = new JsonLoadSettings { DuplicatePropertyNamesHandling = DuplicatePropertyNamesHandling.Throw }; + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + await ExceptionAssert.ThrowsAsync( async () => await JToken.ReadFromAsync(reader, settings)); + } + } + +} #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs index d5092ca0..c2206a63 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs @@ -1743,5 +1743,32 @@ third line", jsonTextReader.Value); { } } + + [Test] + public void ThrowOnDuplicateKeysDeserializing() + { + string json = @" + { + ""a"": 1, + ""b"": [ + { + ""c"": { + ""d"": 1, + ""d"": ""2"" + } + } + ] + } + "; + + JsonLoadSettings settings = new JsonLoadSettings {DuplicatePropertyNamesHandling = DuplicatePropertyNamesHandling.Throw}; + + ExceptionAssert.Throws(() => JObject.Parse(json, settings)); + ExceptionAssert.Throws(() => + { + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + JToken.ReadFrom(reader, settings); + }); + } } } diff --git a/Src/Newtonsoft.Json/Linq/DuplicatePropertyNamesHandling.cs b/Src/Newtonsoft.Json/Linq/DuplicatePropertyNamesHandling.cs new file mode 100644 index 00000000..08b24ed7 --- /dev/null +++ b/Src/Newtonsoft.Json/Linq/DuplicatePropertyNamesHandling.cs @@ -0,0 +1,42 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Linq +{ + /// + /// Specifies how duplicate property names are handled when loading JSON. + /// + public enum DuplicatePropertyNamesHandling + { + /// + /// Ignore duplicate properties, use only last value (default) + /// + Ignore = 0, + /// + /// Throw exception + /// + Throw = 1 + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JContainer.Async.cs b/Src/Newtonsoft.Json/Linq/JContainer.Async.cs index ec235c14..cd00d47f 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.Async.cs @@ -160,6 +160,10 @@ namespace Newtonsoft.Json.Linq } else { + if (settings != null && settings.DuplicatePropertyNamesHandling == DuplicatePropertyNamesHandling.Throw) + { + throw JsonException.Create(lineInfo, property.Path, $"Property with the same name ('{propertyName}') already exists"); + } existingPropertyWithName.Replace(property); } parent = property; diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index d586aaf0..4fa19b5f 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -849,6 +849,10 @@ namespace Newtonsoft.Json.Linq } else { + if (settings != null && settings.DuplicatePropertyNamesHandling == DuplicatePropertyNamesHandling.Throw) + { + throw JsonException.Create(lineInfo, property.Path, $"Property with the same name ('{propertyName}') already exists"); + } existingPropertyWithName.Replace(property); } parent = property; diff --git a/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs b/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs index 3e392c83..4204ffac 100644 --- a/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs +++ b/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs @@ -9,6 +9,7 @@ namespace Newtonsoft.Json.Linq { private CommentHandling _commentHandling; private LineInfoHandling _lineInfoHandling; + private DuplicatePropertyNamesHandling _duplicatePropertyNamesHandling; /// /// Initializes a new instance of the class. @@ -17,6 +18,7 @@ namespace Newtonsoft.Json.Linq { _lineInfoHandling = LineInfoHandling.Load; _commentHandling = CommentHandling.Ignore; + _duplicatePropertyNamesHandling = DuplicatePropertyNamesHandling.Ignore; } /// @@ -54,5 +56,23 @@ namespace Newtonsoft.Json.Linq _lineInfoHandling = value; } } + + /// + /// Gets or sets how duplicate property names are handled when loading JSON. + /// + /// The JSON duplicate property names handling. + public DuplicatePropertyNamesHandling DuplicatePropertyNamesHandling + { + get => this._duplicatePropertyNamesHandling; + set + { + if (value< DuplicatePropertyNamesHandling.Ignore|| value> DuplicatePropertyNamesHandling.Throw) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + + this._duplicatePropertyNamesHandling = value; + } + } } } \ No newline at end of file