From 82025bc5b712bc6465860cd0dd80c0d3793be0ed Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 7 Dec 2014 16:08:27 +1300 Subject: [PATCH] -Added JContainer.DescendantsAndSelf -Added CurrentToken to JTokenReader --- .../Linq/AnnotationsTests.cs | 250 ++++++++++++++ .../Linq/JTokenReaderTest.cs | 22 +- Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs | 30 ++ .../Newtonsoft.Json.Tests.csproj | 1 + Src/Newtonsoft.Json/Bson/BsonReader.cs | 2 +- Src/Newtonsoft.Json/JsonReader.cs | 2 +- Src/Newtonsoft.Json/Linq/JContainer.cs | 17 + Src/Newtonsoft.Json/Linq/JToken.cs | 304 +++++++++++++++++- Src/Newtonsoft.Json/Linq/JTokenReader.cs | 18 +- .../JsonSerializerInternalReader.cs | 2 +- Src/Newtonsoft.Json/Utilities/ConvertUtils.cs | 4 - .../Utilities/TypeExtensions.cs | 8 + 12 files changed, 639 insertions(+), 21 deletions(-) create mode 100644 Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs diff --git a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs new file mode 100644 index 00000000..10a4a3da --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using NUnit.Framework; + +namespace Newtonsoft.Json.Tests.Linq +{ + [TestFixture] + public class AnnotationsTests : TestFixtureBase + { + [Test] + public void AddAnnotation() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + + string s = o.Annotation(); + Assert.AreEqual("A string!", s); + + s = (string)o.Annotation(typeof(string)); + Assert.AreEqual("A string!", s); + } + + [Test] + public void AddAnnotation_MultipleOfTheSameType() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation("Another string!"); + + string s = o.Annotation(); + Assert.AreEqual("A string!", s); + + s = (string)o.Annotation(typeof(string)); + Assert.AreEqual("A string!", s); + } + + [Test] + public void AddAnnotation_MultipleOfDifferentTypes() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation(new Uri("http://www.google.com/")); + + string s = o.Annotation(); + Assert.AreEqual("A string!", s); + + s = (string)o.Annotation(typeof(string)); + Assert.AreEqual("A string!", s); + + Uri i = o.Annotation(); + Assert.AreEqual(new Uri("http://www.google.com/"), i); + + i = (Uri)o.Annotation(typeof(Uri)); + Assert.AreEqual(new Uri("http://www.google.com/"), i); + } + + [Test] + public void GetAnnotation_NeverSet() + { + JObject o = new JObject(); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + s = (string)o.Annotation(typeof(string)); + Assert.AreEqual(null, s); + } + + [Test] + public void GetAnnotations() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation("A string 2!"); + o.AddAnnotation("A string 3!"); + + IList l = o.Annotations().ToList(); + + Assert.AreEqual(3, l.Count); + Assert.AreEqual("A string!", l[0]); + Assert.AreEqual("A string 2!", l[1]); + Assert.AreEqual("A string 3!", l[2]); + + l = o.Annotations(typeof(string)).Cast().ToList(); + + Assert.AreEqual(3, l.Count); + Assert.AreEqual("A string!", l[0]); + Assert.AreEqual("A string 2!", l[1]); + Assert.AreEqual("A string 3!", l[2]); + } + + [Test] + public void GetAnnotations_MultipleTypes() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation("A string 2!"); + o.AddAnnotation("A string 3!"); + o.AddAnnotation(new Uri("http://www.google.com/")); + + IList l = o.Annotations().ToList(); + + Assert.AreEqual(4, l.Count); + Assert.AreEqual("A string!", l[0]); + Assert.AreEqual("A string 2!", l[1]); + Assert.AreEqual("A string 3!", l[2]); + Assert.AreEqual(new Uri("http://www.google.com/"), l[3]); + + l = o.Annotations(typeof(object)).ToList(); + + Assert.AreEqual(4, l.Count); + Assert.AreEqual("A string!", l[0]); + Assert.AreEqual("A string 2!", l[1]); + Assert.AreEqual("A string 3!", l[2]); + Assert.AreEqual(new Uri("http://www.google.com/"), l[3]); + } + + [Test] + public void RemoveAnnotation() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + + o.RemoveAnnotations(); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + } + + [Test] + public void RemoveAnnotation_NonGeneric() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + + o.RemoveAnnotations(typeof(string)); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + s = (string)o.Annotation(typeof(string)); + Assert.AreEqual(null, s); + } + + [Test] + public void RemoveAnnotation_Multiple() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation("A string 2!"); + o.AddAnnotation("A string 3!"); + + o.RemoveAnnotations(); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + o.AddAnnotation("A string 4!"); + + s = o.Annotation(); + Assert.AreEqual("A string 4!", s); + + Uri i = (Uri)o.Annotation(typeof(Uri)); + Assert.AreEqual(null, i); + } + + [Test] + public void RemoveAnnotation_MultipleCalls() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation(new Uri("http://www.google.com/")); + + o.RemoveAnnotations(); + o.RemoveAnnotations(); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + Uri i = o.Annotation(); + Assert.AreEqual(null, i); + } + + [Test] + public void RemoveAnnotation_Multiple_NonGeneric() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation("A string 2!"); + + o.RemoveAnnotations(typeof(string)); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + } + + [Test] + public void RemoveAnnotation_MultipleCalls_NonGeneric() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation(new Uri("http://www.google.com/")); + + o.RemoveAnnotations(typeof(string)); + o.RemoveAnnotations(typeof(Uri)); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + Uri i = o.Annotation(); + Assert.AreEqual(null, i); + } + + [Test] + public void RemoveAnnotation_MultipleWithDifferentTypes() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation(new Uri("http://www.google.com/")); + + o.RemoveAnnotations(); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + Uri i = o.Annotation(); + Assert.AreEqual(new Uri("http://www.google.com/"), i); + } + + [Test] + public void RemoveAnnotation_MultipleWithDifferentTypes_NonGeneric() + { + JObject o = new JObject(); + o.AddAnnotation("A string!"); + o.AddAnnotation(new Uri("http://www.google.com/")); + + o.RemoveAnnotations(typeof(string)); + + string s = o.Annotation(); + Assert.AreEqual(null, s); + + Uri i = o.Annotation(); + Assert.AreEqual(new Uri("http://www.google.com/"), i); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs index d1448bfb..42a6c059 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs @@ -208,8 +208,6 @@ namespace Newtonsoft.Json.Tests.Linq ] }"; - StringReader sr = new StringReader(input); - JObject o = JObject.Parse(input); using (JTokenReader jsonReader = new JTokenReader(o)) @@ -220,12 +218,14 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(0, lineInfo.LineNumber); Assert.AreEqual(0, lineInfo.LinePosition); Assert.AreEqual(false, lineInfo.HasLineInfo()); + Assert.AreEqual(null, jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject); Assert.AreEqual(1, lineInfo.LineNumber); Assert.AreEqual(1, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o, jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName); @@ -233,6 +233,7 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(2, lineInfo.LineNumber); Assert.AreEqual(7, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o.Property("CPU"), jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.String); @@ -240,6 +241,7 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(2, lineInfo.LineNumber); Assert.AreEqual(15, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o.Property("CPU").Value, jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName); @@ -247,12 +249,14 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(3, lineInfo.LineNumber); Assert.AreEqual(10, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o.Property("Drives"), jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray); Assert.AreEqual(3, lineInfo.LineNumber); Assert.AreEqual(12, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o.Property("Drives").Value, jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.String); @@ -260,6 +264,7 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(4, lineInfo.LineNumber); Assert.AreEqual(22, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o["Drives"][0], jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.String); @@ -267,21 +272,29 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(5, lineInfo.LineNumber); Assert.AreEqual(30, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o["Drives"][1], jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray); Assert.AreEqual(3, lineInfo.LineNumber); Assert.AreEqual(12, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o["Drives"], jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject); Assert.AreEqual(1, lineInfo.LineNumber); Assert.AreEqual(1, lineInfo.LinePosition); Assert.AreEqual(true, lineInfo.HasLineInfo()); + Assert.AreEqual(o, jsonReader.CurrentToken); jsonReader.Read(); Assert.AreEqual(jsonReader.TokenType, JsonToken.None); + Assert.AreEqual(null, jsonReader.CurrentToken); + + jsonReader.Read(); + Assert.AreEqual(jsonReader.TokenType, JsonToken.None); + Assert.AreEqual(null, jsonReader.CurrentToken); } } @@ -471,15 +484,18 @@ namespace Newtonsoft.Json.Tests.Linq JObject o = JObject.Parse(json); - JsonReader reader = o.CreateReader(); + JTokenReader reader = (JTokenReader)o.CreateReader(); Assert.IsTrue(reader.Read()); Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + Assert.AreEqual(o, reader.CurrentToken); Assert.IsTrue(reader.Read()); Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual(o.Property("Name"), reader.CurrentToken); reader.ReadAsInt32(); + Assert.AreEqual(o["Name"], reader.CurrentToken); Assert.AreEqual(JsonToken.Integer, reader.TokenType); Assert.AreEqual(typeof(int), reader.ValueType); Assert.AreEqual(1, reader.Value); diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index caff897b..d9465a79 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; +using System.Xml.Linq; #if !(NET20 || NET35 || PORTABLE || ASPNETCORE50) using System.Numerics; #endif @@ -717,6 +718,35 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(3, (int)descendants[descendants.Count - 1]); } + [Test] + public void DescendantsAndSelf() + { + XElement e = new XElement("name"); + e.Add(new XElement("child")); + + var x = e.DescendantsAndSelf().ToList(); + Assert.AreEqual(2, x.Count); + Assert.AreEqual(e, x[0]); + Assert.AreEqual(e.Element("child"), x[1]); + + JArray a = + new JArray( + 5, + new JArray(1), + new JArray(1, 2), + new JArray(1, 2, 3) + ); + + List descendantsAndSelf = a.DescendantsAndSelf().ToList(); + Assert.AreEqual(11, descendantsAndSelf.Count()); + Assert.AreEqual(a, descendantsAndSelf[0]); + Assert.AreEqual(5, (int)descendantsAndSelf[1]); + Assert.IsTrue(JToken.DeepEquals(new JArray(1, 2, 3), descendantsAndSelf[descendantsAndSelf.Count - 4])); + Assert.AreEqual(1, (int)descendantsAndSelf[descendantsAndSelf.Count - 3]); + Assert.AreEqual(2, (int)descendantsAndSelf[descendantsAndSelf.Count - 2]); + Assert.AreEqual(3, (int)descendantsAndSelf[descendantsAndSelf.Count - 1]); + } + [Test] public void CreateWriter() { diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index c074fe29..598cc005 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -213,6 +213,7 @@ + diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs index 477b778e..9f07f3fc 100644 --- a/Src/Newtonsoft.Json/Bson/BsonReader.cs +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -35,7 +35,7 @@ using Newtonsoft.Json.Linq; namespace Newtonsoft.Json.Bson { /// - /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data. /// public class BsonReader : JsonReader { diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index c14c4da1..9fb6e77b 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -39,7 +39,7 @@ using System.Linq; namespace Newtonsoft.Json { /// - /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data. /// public abstract class JsonReader : IDisposable { diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 3d16778d..cb662d99 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -272,6 +272,23 @@ namespace Newtonsoft.Json.Linq /// An containing the descendant tokens of the . public IEnumerable Descendants() { + return GetDescendants(false); + } + + /// + /// Returns a collection of the tokens that contain this token, and all descendant tokens of this token, in document order. + /// + /// An containing this token, and all the descendant tokens of the . + public IEnumerable DescendantsAndSelf() + { + return GetDescendants(true); + } + + internal IEnumerable GetDescendants(bool self) + { + if (self) + yield return this; + foreach (JToken o in ChildrenTokens) { yield return o; diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 9778949c..000853f5 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -59,13 +59,15 @@ namespace Newtonsoft.Json.Linq , IDynamicMetaObjectProvider #endif { + private static JTokenEqualityComparer _equalityComparer; + private JContainer _parent; private JToken _previous; private JToken _next; - private static JTokenEqualityComparer _equalityComparer; + private object _annotations; - private int? _lineNumber; - private int? _linePosition; + //private int? _lineNumber; + //private int? _linePosition; private static readonly JTokenType[] BooleanTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean }; private static readonly JTokenType[] NumberTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean }; @@ -1923,25 +1925,50 @@ namespace Newtonsoft.Json.Linq SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition); } + private class LineInfoAnnotation + { + internal readonly int LineNumber; + internal readonly int LinePosition; + + public LineInfoAnnotation(int lineNumber, int linePosition) + { + LineNumber = lineNumber; + LinePosition = linePosition; + } + } + internal void SetLineInfo(int lineNumber, int linePosition) { - _lineNumber = lineNumber; - _linePosition = linePosition; + AddAnnotation(new LineInfoAnnotation(lineNumber, linePosition)); } bool IJsonLineInfo.HasLineInfo() { - return (_lineNumber != null && _linePosition != null); + return (Annotation() != null); } int IJsonLineInfo.LineNumber { - get { return _lineNumber ?? 0; } + get + { + LineInfoAnnotation annotation = Annotation(); + if (annotation != null) + return annotation.LineNumber; + + return 0; + } } int IJsonLineInfo.LinePosition { - get { return _linePosition ?? 0; } + get + { + LineInfoAnnotation annotation = Annotation(); + if (annotation != null) + return annotation.LinePosition; + + return 0; + } } /// @@ -2047,5 +2074,266 @@ namespace Newtonsoft.Json.Linq { return CloneToken(); } + + /// + /// Adds an object to the annotation list of this . + /// + /// The annotation to add. + public void AddAnnotation(object annotation) + { + if (annotation == null) + throw new ArgumentNullException("annotation"); + + if (_annotations == null) + { + _annotations = (annotation is object[]) ? new [] { annotation } : annotation; + } + else + { + object[] annotations = _annotations as object[]; + if (annotations == null) + { + _annotations = new [] { _annotations, annotation }; + } + else + { + int index = 0; + while (index < annotations.Length && annotations[index] != null) + { + index++; + } + if (index == annotations.Length) + { + Array.Resize(ref annotations, index * 2); + _annotations = annotations; + } + annotations[index] = annotation; + } + } + } + + /// + /// Get the first annotation object of the specified type from this . + /// + /// The type of the annotation to retrieve. + /// The first annotation object that matches the specified type, or null if no annotation is of the specified type. + public T Annotation() where T : class + { + if (_annotations != null) + { + object[] annotations = _annotations as object[]; + if (annotations == null) + { + return (_annotations as T); + } + for (int i = 0; i < annotations.Length; i++) + { + object annotation = annotations[i]; + if (annotation == null) + break; + + T local = annotation as T; + if (local != null) + return local; + } + } + + return default(T); + } + + /// + /// Gets the first annotation object of the specified type from this . + /// + /// The of the annotation to retrieve. + /// The first annotation object that matches the specified type, or null if no annotation is of the specified type. + public object Annotation(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + + if (_annotations != null) + { + object[] annotations = _annotations as object[]; + if (annotations == null) + { + if (type.IsInstanceOfType(_annotations)) + return _annotations; + } + else + { + for (int i = 0; i < annotations.Length; i++) + { + object o = annotations[i]; + if (o == null) + break; + + if (type.IsInstanceOfType(o)) + return o; + } + } + } + + return null; + } + + /// + /// Gets a collection of annotations of the specified type for this . + /// + /// The type of the annotations to retrieve. + /// An that contains the annotations for this . + public IEnumerable Annotations() where T : class + { + if (_annotations == null) + yield break; + + object[] annotations = _annotations as object[]; + if (annotations != null) + { + for (int i = 0; i < annotations.Length; i++) + { + object o = annotations[i]; + if (o == null) + break; + + T casted = o as T; + if (casted != null) + yield return casted; + } + yield break; + } + + T annotation = _annotations as T; + if (annotation == null) + yield break; + + yield return annotation; + } + + /// + /// Gets a collection of annotations of the specified type for this . + /// + /// The of the annotations to retrieve. + /// An of that contains the annotations that match the specified type for this . + public IEnumerable Annotations(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + + if (_annotations == null) + yield break; + + object[] annotations = _annotations as object[]; + if (annotations != null) + { + for (int i = 0; i < annotations.Length; i++) + { + object o = annotations[i]; + if (o == null) + break; + + if (type.IsInstanceOfType(o)) + yield return o; + } + yield break; + } + + if (!type.IsInstanceOfType(_annotations)) + yield break; + + yield return _annotations; + } + + /// + /// Removes the annotations of the specified type from this . + /// + /// The type of annotations to remove. + public void RemoveAnnotations() where T : class + { + if (_annotations != null) + { + object[] annotations = _annotations as object[]; + if (annotations == null) + { + if (_annotations is T) + _annotations = null; + } + else + { + int index = 0; + int keepCount = 0; + while (index < annotations.Length) + { + object obj2 = annotations[index]; + if (obj2 == null) + break; + + if (!(obj2 is T)) + annotations[keepCount++] = obj2; + + index++; + } + + if (keepCount != 0) + { + while (keepCount < index) + { + annotations[keepCount++] = null; + } + } + else + { + _annotations = null; + } + } + } + } + + /// + /// Removes the annotations of the specified type from this . + /// + /// The of annotations to remove. + public void RemoveAnnotations(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + + if (_annotations != null) + { + object[] annotations = _annotations as object[]; + if (annotations == null) + { + if (type.IsInstanceOfType(_annotations)) + _annotations = null; + } + else + { + int index = 0; + int keepCount = 0; + while (index < annotations.Length) + { + object o = annotations[index]; + if (o == null) + break; + + if (!type.IsInstanceOfType(o)) + annotations[keepCount++] = o; + + index++; + } + + if (keepCount != 0) + { + while (keepCount < index) + { + annotations[keepCount++] = null; + } + } + else + { + _annotations = null; + } + } + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JTokenReader.cs b/Src/Newtonsoft.Json/Linq/JTokenReader.cs index dbeb0942..726bd02a 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenReader.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenReader.cs @@ -29,14 +29,22 @@ using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Linq { /// - /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. + /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data. /// public class JTokenReader : JsonReader, IJsonLineInfo { private readonly string _initialPath; private readonly JToken _root; private JToken _parent; - internal JToken _current; + private JToken _current; + + /// + /// Gets the at the reader's current position. + /// + public JToken CurrentToken + { + get { return _current; } + } /// /// Initializes a new instance of the class. @@ -47,7 +55,6 @@ namespace Newtonsoft.Json.Linq ValidationUtils.ArgumentNotNull(token, "token"); _root = token; - _current = token; } internal JTokenReader(JToken token, string initialPath) @@ -118,6 +125,9 @@ namespace Newtonsoft.Json.Linq { if (CurrentState != State.Start) { + if (_current == null) + return false; + JContainer container = _current as JContainer; if (container != null && _parent != container) return ReadInto(container); @@ -125,6 +135,7 @@ namespace Newtonsoft.Json.Linq return ReadOver(_current); } + _current = _root; SetToken(_current); return true; } @@ -165,6 +176,7 @@ namespace Newtonsoft.Json.Linq private bool ReadToEnd() { + _current = null; SetToken(JsonToken.None); return false; } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 697a5c37..24403d16 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -526,7 +526,7 @@ namespace Newtonsoft.Json.Serialization if (reader.TokenType == JsonToken.StartObject) { - JObject current = (JObject)reader._current; + JObject current = (JObject)reader.CurrentToken; JToken refToken = current[JsonTypeReflector.RefPropertyName]; if (refToken != null) diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs index be8f2900..dc5d4706 100644 --- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs @@ -74,20 +74,16 @@ namespace Newtonsoft.Json.Utilities DoubleNullable = 25, DateTime = 26, DateTimeNullable = 27, -#if !NET20 DateTimeOffset = 28, DateTimeOffsetNullable = 29, -#endif Decimal = 30, DecimalNullable = 31, Guid = 32, GuidNullable = 33, TimeSpan = 34, TimeSpanNullable = 35, -#if !(PORTABLE || NET35 || NET20) BigInteger = 36, BigIntegerNullable = 37, -#endif Uri = 38, String = 39, Bytes = 40, diff --git a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs index 3618caee..3b4d1454 100644 --- a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs +++ b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs @@ -76,6 +76,14 @@ namespace Newtonsoft.Json.Utilities { return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); } + + public static bool IsInstanceOfType(this Type type, object o) + { + if (o == null) + return false; + + return IsAssignableFrom(type, o.GetType()); + } #endif public static MethodInfo Method(this Delegate d)