diff --git a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs index 28af83764..6fa31be27 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs @@ -308,6 +308,61 @@ private void AssertCloneCopy(JToken t, T annotation) where T : class Assert.AreEqual(annotation, t.DeepClone().Annotation()); } + [Test] + public void MultipleAnnotationsAreNotCopiedWithSetting() + { + Version version = new Version(1, 2, 3, 4); + JsonCloneSettings settings = new JsonCloneSettings() { CopyAnnotations = false }; + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JObject o2 = (JObject)o.DeepClone(settings); + Assert.IsNull(o2.Annotation()); + Assert.AreEqual(0, o2.Annotations().Count()); + + JArray a = new JArray(); + a.AddAnnotation("string!"); + a.AddAnnotation(version); + + JArray a2 = (JArray)a.DeepClone(settings); + Assert.IsNull(a2.Annotation()); + Assert.AreEqual(0, a2.Annotations().Count()); + + JProperty p = new JProperty("test"); + p.AddAnnotation("string!"); + p.AddAnnotation(version); + + JProperty p2 = (JProperty)p.DeepClone(settings); + Assert.IsNull(p2.Annotation()); + Assert.AreEqual(0, p2.Annotations().Count()); + + JRaw r = new JRaw("test"); + r.AddAnnotation("string!"); + r.AddAnnotation(version); + + JRaw r2 = (JRaw)r.DeepClone(settings); + Assert.IsNull(r2.Annotation()); + Assert.AreEqual(0, r2.Annotations().Count()); + + JConstructor c = new JConstructor("test"); + c.AddAnnotation("string!"); + c.AddAnnotation(version); + + JConstructor c2 = (JConstructor)c.DeepClone(settings); + Assert.IsNull(c2.Annotation()); + Assert.AreEqual(0, c2.Annotations().Count()); + + JValue v = new JValue("test"); + v.AddAnnotation("string!"); + v.AddAnnotation(version); + + JValue v2 = (JValue)v.DeepClone(settings); + Assert.IsNull(v2.Annotation()); + Assert.AreEqual(0, v2.Annotations().Count()); + } + #if !NET20 [Test] public void Example() diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index 241a56045..d427b1be2 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -65,8 +65,9 @@ public JArray() /// Initializes a new instance of the class from another object. /// /// A object to copy from. - public JArray(JArray other) - : base(other) + /// A object to configure cloning settings. + public JArray(JArray other, JsonCloneSettings? settings = null) + : base(other, settings) { } @@ -78,7 +79,7 @@ public JArray(params object[] content) : this((object)content) { } - + /// /// Initializes a new instance of the class with the specified content. /// @@ -93,9 +94,9 @@ internal override bool DeepEquals(JToken node) return (node is JArray t && ContentsEqual(t)); } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JArray(this); + return new JArray(this, settings); } /// diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index f2aa86182..a989e8117 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -96,8 +96,9 @@ public JConstructor() /// Initializes a new instance of the class from another object. /// /// A object to copy from. - public JConstructor(JConstructor other) - : base(other) + /// A object to configure cloning settings. + public JConstructor(JConstructor other, JsonCloneSettings? settings = null) + : base(other, settings) { _name = other.Name; } @@ -147,9 +148,9 @@ internal override bool DeepEquals(JToken node) return (node is JConstructor c && _name == c.Name && ContentsEqual(c)); } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JConstructor(this); + return new JConstructor(this, settings); } /// diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index f9447cd5d..565f8b3df 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -106,7 +106,7 @@ internal JContainer() { } - internal JContainer(JContainer other) + internal JContainer(JContainer other, JsonCloneSettings? settings = null) : this() { ValidationUtils.ArgumentNotNull(other, nameof(other)); @@ -118,7 +118,10 @@ internal JContainer(JContainer other) i++; } - CopyAnnotations(this, other); + if (settings?.CopyAnnotations ?? true) + { + CopyAnnotations(this, other); + } } internal void CheckReentrancy() diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index 872c8ae7c..e9d9018f0 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -92,8 +92,9 @@ public JObject() /// Initializes a new instance of the class from another object. /// /// A object to copy from. - public JObject(JObject other) - : base(other) + /// A object to configure cloning settings. + public JObject(JObject other, JsonCloneSettings? settings = null) + : base(other, settings) { } @@ -244,9 +245,9 @@ internal void InternalPropertyChanging(JProperty childProperty) #endif } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JObject(this); + return new JObject(this, settings); } /// diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index 3c738cf52..20175fbd5 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -186,8 +186,9 @@ public JToken Value /// Initializes a new instance of the class from another object. /// /// A object to copy from. - public JProperty(JProperty other) - : base(other) + /// A object to configure cloning settings. + public JProperty(JProperty other, JsonCloneSettings? settings = null) + : base(other, settings) { _name = other.Name; } @@ -282,9 +283,9 @@ internal override bool DeepEquals(JToken node) return (node is JProperty t && _name == t.Name && ContentsEqual(t)); } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JProperty(this); + return new JProperty(this, settings); } /// diff --git a/Src/Newtonsoft.Json/Linq/JRaw.cs b/Src/Newtonsoft.Json/Linq/JRaw.cs index 02ca51fd1..904b89942 100644 --- a/Src/Newtonsoft.Json/Linq/JRaw.cs +++ b/Src/Newtonsoft.Json/Linq/JRaw.cs @@ -37,8 +37,9 @@ public partial class JRaw : JValue /// Initializes a new instance of the class from another object. /// /// A object to copy from. - public JRaw(JRaw other) - : base(other) + /// A object to configure cloning settings. + public JRaw(JRaw other, JsonCloneSettings? settings = null) + : base(other, settings) { } @@ -67,9 +68,9 @@ public static JRaw Create(JsonReader reader) } } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JRaw(this); + return new JRaw(this, settings); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 336d748aa..611f708ef 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -131,7 +131,7 @@ public JToken Root } } - internal abstract JToken CloneToken(); + internal abstract JToken CloneToken(JsonCloneSettings? settings = null); internal abstract bool DeepEquals(JToken node); /// @@ -2446,6 +2446,16 @@ public JToken DeepClone() return CloneToken(); } + /// + /// Creates a new instance of the . All child tokens are recursively cloned. + /// + /// A object to configure cloning settings. + /// A new instance of the . + public JToken DeepClone(JsonCloneSettings settings) + { + return CloneToken(settings); + } + /// /// Adds an object to the annotation list of this . /// diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 09ed1fd42..23f2e0212 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -61,10 +61,14 @@ internal JValue(object? value, JTokenType type) /// Initializes a new instance of the class from another object. /// /// A object to copy from. - public JValue(JValue other) + /// A object to configure cloning settings. + public JValue(JValue other, JsonCloneSettings? settings = null) : this(other.Value, other.Type) { - CopyAnnotations(this, other); + if (settings?.CopyAnnotations ?? true) + { + CopyAnnotations(this, other); + } } /// @@ -557,9 +561,9 @@ private static bool Operation(ExpressionType operation, object? objA, object? ob } #endif - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JValue(this); + return new JValue(this, settings); } /// diff --git a/Src/Newtonsoft.Json/Linq/JsonCloneSettings.cs b/Src/Newtonsoft.Json/Linq/JsonCloneSettings.cs new file mode 100644 index 000000000..cae4507ee --- /dev/null +++ b/Src/Newtonsoft.Json/Linq/JsonCloneSettings.cs @@ -0,0 +1,18 @@ +using System; + +namespace Newtonsoft.Json.Linq +{ + /// + /// Specifies the settings used when selecting JSON. + /// + public class JsonCloneSettings + { + /// + /// Gets or sets a flag that indicates whether to copy annotations when cloning a JToken. + /// + /// + /// A flag that indicates whether to copy annotations when cloning a JToken. + /// + public bool CopyAnnotations { get; set; } + } +} \ No newline at end of file