From ff5ffb2832b2297502d1ff44efb2e16c57a648b7 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 1 Jan 2021 19:25:57 +1300 Subject: [PATCH] Copy annotations when cloning elements (#2442) --- .../Linq/AnnotationsTests.cs | 51 +++++++++++++++++++ Src/Newtonsoft.Json/Linq/JContainer.cs | 2 + Src/Newtonsoft.Json/Linq/JToken.cs | 12 +++++ Src/Newtonsoft.Json/Linq/JValue.cs | 1 + 4 files changed, 66 insertions(+) diff --git a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs index ff3657dc..28af8376 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs @@ -257,6 +257,57 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(new Uri("http://www.google.com/"), i); } + [Test] + public void AnnotationsAreCopied() + { + JObject o = new JObject(); + o.AddAnnotation("string!"); + AssertCloneCopy(o, "string!"); + + JProperty p = new JProperty("Name", "Content"); + p.AddAnnotation("string!"); + AssertCloneCopy(p, "string!"); + + JArray a = new JArray(); + a.AddAnnotation("string!"); + AssertCloneCopy(a, "string!"); + + JConstructor c = new JConstructor("Test"); + c.AddAnnotation("string!"); + AssertCloneCopy(c, "string!"); + + JValue v = new JValue(true); + v.AddAnnotation("string!"); + AssertCloneCopy(v, "string!"); + + JRaw r = new JRaw("raw"); + r.AddAnnotation("string!"); + AssertCloneCopy(r, "string!"); + } + + [Test] + public void MultipleAnnotationsAreCopied() + { + Version version = new Version(1, 2, 3, 4); + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JObject o2 = (JObject)o.DeepClone(); + Assert.AreEqual("string!", o2.Annotation()); + Assert.AreEqual(version, o2.Annotation()); + + o2.RemoveAnnotations(); + Assert.AreEqual(1, o.Annotations().Count()); + Assert.AreEqual(0, o2.Annotations().Count()); + } + + private void AssertCloneCopy(JToken t, T annotation) where T : class + { + Assert.AreEqual(annotation, t.DeepClone().Annotation()); + } + #if !NET20 [Test] public void Example() diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 6afeca6d..ac3a18a0 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -117,6 +117,8 @@ namespace Newtonsoft.Json.Linq AddInternal(i, child, false); i++; } + + CopyAnnotations(this, other); } internal void CheckReentrancy() diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 7487b9a4..8242f7f9 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -2704,5 +2704,17 @@ namespace Newtonsoft.Json.Linq } } } + + internal void CopyAnnotations(JToken target, JToken source) + { + if (source._annotations is object[] annotations) + { + target._annotations = annotations.ToArray(); + } + else + { + target._annotations = source._annotations; + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index d39ea121..27d5de88 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -64,6 +64,7 @@ namespace Newtonsoft.Json.Linq public JValue(JValue other) : this(other.Value, other.Type) { + CopyAnnotations(this, other); } ///