diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 0076a546..9be99ab5 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -1811,5 +1811,31 @@ bye", reader.Value); Assert.AreEqual(JsonToken.Float, reader.TokenType); Assert.AreEqual(32m, reader.Value); } + + [Test] + public void ParseNumbers() + { + string json = @"[0,1,2 , 3]"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + reader.Read(); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + reader.Read(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + + reader.Read(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + + reader.Read(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + + reader.Read(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + + reader.Read(); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index 0793cb61..614bd083 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -29,6 +29,7 @@ using System.Text; using NUnit.Framework; using Newtonsoft.Json; using System.IO; +using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Tests { @@ -618,5 +619,30 @@ _____'propertyName': NaN Assert.AreEqual(expected, result); } + + [Test] + public void BuildStateArray() + { + JsonWriter.State[][] stateArray = JsonWriter.BuildStateArray(); + + var valueStates = JsonWriter.StateArrayTempate[7]; + + foreach (JsonToken valueToken in EnumUtils.GetValues(typeof(JsonToken))) + { + switch (valueToken) + { + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.String: + case JsonToken.Boolean: + case JsonToken.Null: + case JsonToken.Undefined: + case JsonToken.Date: + case JsonToken.Bytes: + Assert.AreEqual(valueStates, stateArray[(int)valueToken], "Error for " + valueToken + " states."); + break; + } + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs index 89fcdcdc..97af7d1c 100644 --- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.Serialization; using System.Web.Script.Serialization; using System.Xml.Linq; @@ -35,8 +36,19 @@ namespace Newtonsoft.Json.Tests public class PerformanceTests : TestFixtureBase { - private const int Iterations = 100; - //private const int Iterations = 5000; + //private const int Iterations = 100; + private const int Iterations = 5000; + + private static SimpleObject CreateSimpleObject() + { + return new SimpleObject + { + Name = "Simple-1", + Id = 2311, + Address = "Planet Earth", + Scores = new int[] { 82,96,49,40,38,38,78,96,2,39 } + }; + } #region Data private const string BsonHex = @@ -51,6 +63,9 @@ namespace Newtonsoft.Json.Tests private const string JsonText = @"{""strings"":[null,""Markus egger ]><[, (2nd)"",null],""dictionary"":{""Val & asd1"":1,""Val2 & asd1"":3,""Val3 & asd1"":4},""Name"":""Rick"",""Now"":""\/Date(1262301136080+1300)\/"",""BigNumber"":34123123123.121,""Address1"":{""Street"":""fff Street"",""Phone"":""(503) 814-6335"",""Entered"":""\/Date(1264025536080+1300)\/""},""Addresses"":[{""Street"":""\u001farray(SimpleJsonText); + } + [Test] public void Serialize() { TestClass test = CreateSerializationObject(); - BenchmarkSerializeMethod(SerializeMethod.DataContractSerializer, test); - BenchmarkSerializeMethod(SerializeMethod.BinaryFormatter, test); - BenchmarkSerializeMethod(SerializeMethod.JavaScriptSerializer, test); - BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, test); - BenchmarkSerializeMethod(SerializeMethod.JsonNet, test); - BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, test); + SerializeTests(test); + } + + private void SerializeTests(object value) + { + //BenchmarkSerializeMethod(SerializeMethod.DataContractSerializer, value); + ////BenchmarkSerializeMethod(SerializeMethod.BinaryFormatter, value); + //BenchmarkSerializeMethod(SerializeMethod.JavaScriptSerializer, value); + //BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, value); + BenchmarkSerializeMethod(SerializeMethod.JsonNet, value); + //BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, value); } [Test] @@ -80,12 +114,17 @@ namespace Newtonsoft.Json.Tests { BenchmarkDeserializeMethod(SerializeMethod.DataContractSerializer, XmlText); BenchmarkDeserializeMethod(SerializeMethod.BinaryFormatter, MiscellaneousUtils.HexToBytes(BinaryFormatterHex)); - BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, JsonText); - BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, JsonText); - BenchmarkDeserializeMethod(SerializeMethod.JsonNet, JsonText); + DeserializeTests(JsonText); BenchmarkDeserializeMethod(SerializeMethod.JsonNetBinary, MiscellaneousUtils.HexToBytes(BsonHex)); } + public void DeserializeTests(string json) + { + BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, json); + BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, json); + BenchmarkDeserializeMethod(SerializeMethod.JsonNet, json); + } + [Test] public void SerializeSizeNormal() { @@ -722,6 +761,22 @@ namespace Newtonsoft.Json.Tests } private DateTime _Entered = DateTime.Parse("01/01/2007", CultureInfo.CurrentCulture.DateTimeFormat); } + + [DataContract] + public class SimpleObject + { + [DataMember] + public int Id { get; set; } + + [DataMember] + public string Name { get; set; } + + [DataMember] + public string Address { get; set; } + + [DataMember] + public int[] Scores { get; set; } + } #endregion } #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs index 8391e062..569183f1 100644 --- a/Src/Newtonsoft.Json/Bson/BsonReader.cs +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -39,10 +39,10 @@ namespace Newtonsoft.Json.Bson public class BsonReader : JsonReader { private const int MaxCharBytesSize = 128; - private static readonly byte[] _seqRange1 = new byte[] { 0, 127 }; // range of 1-byte sequence - private static readonly byte[] _seqRange2 = new byte[] { 194, 223 }; // range of 2-byte sequence - private static readonly byte[] _seqRange3 = new byte[] { 224, 239 }; // range of 3-byte sequence - private static readonly byte[] _seqRange4 = new byte[] { 240, 244 }; // range of 4-byte sequence + private static readonly byte[] SeqRange1 = new byte[] { 0, 127 }; // range of 1-byte sequence + private static readonly byte[] SeqRange2 = new byte[] { 194, 223 }; // range of 2-byte sequence + private static readonly byte[] SeqRange3 = new byte[] { 224, 239 }; // range of 3-byte sequence + private static readonly byte[] SeqRange4 = new byte[] { 240, 244 }; // range of 4-byte sequence private readonly BinaryReader _reader; private readonly List _stack; @@ -778,10 +778,10 @@ namespace Newtonsoft.Json.Bson private int BytesInSequence(byte b) { - if (b <= _seqRange1[1]) return 1; - if (b >= _seqRange2[0] && b <= _seqRange2[1]) return 2; - if (b >= _seqRange3[0] && b <= _seqRange3[1]) return 3; - if (b >= _seqRange4[0] && b <= _seqRange4[1]) return 4; + if (b <= SeqRange1[1]) return 1; + if (b >= SeqRange2[0] && b <= SeqRange2[1]) return 2; + if (b >= SeqRange3[0] && b <= SeqRange3[1]) return 3; + if (b >= SeqRange4[0] && b <= SeqRange4[1]) return 4; return 0; } diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 65dcba70..cd6a9e22 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -88,9 +88,9 @@ namespace Newtonsoft.Json.Converters return new XmlElementWrapper(_document.CreateElement(elementName)); } - public IXmlElement CreateElement(string qualifiedName, string namespaceURI) + public IXmlElement CreateElement(string qualifiedName, string namespaceUri) { - return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceURI)); + return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri)); } public IXmlNode CreateAttribute(string name, string value) @@ -101,9 +101,9 @@ namespace Newtonsoft.Json.Converters return attribute; } - public IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value) + public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value) { - XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceURI)); + XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri)); attribute.Value = value; return attribute; @@ -138,9 +138,9 @@ namespace Newtonsoft.Json.Converters _element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode); } - public string GetPrefixOfNamespace(string namespaceURI) + public string GetPrefixOfNamespace(string namespaceUri) { - return _element.GetPrefixOfNamespace(namespaceURI); + return _element.GetPrefixOfNamespace(namespaceUri); } } @@ -264,7 +264,7 @@ namespace Newtonsoft.Json.Converters get { return _node.Prefix; } } - public string NamespaceURI + public string NamespaceUri { get { return _node.NamespaceURI; } } @@ -283,9 +283,9 @@ namespace Newtonsoft.Json.Converters IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone); IXmlNode CreateProcessingInstruction(string target, string data); IXmlElement CreateElement(string elementName); - IXmlElement CreateElement(string qualifiedName, string namespaceURI); + IXmlElement CreateElement(string qualifiedName, string namespaceUri); IXmlNode CreateAttribute(string name, string value); - IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value); + IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value); IXmlElement DocumentElement { get; } } @@ -300,7 +300,7 @@ namespace Newtonsoft.Json.Converters internal interface IXmlElement : IXmlNode { void SetAttributeNode(IXmlNode attribute); - string GetPrefixOfNamespace(string namespaceURI); + string GetPrefixOfNamespace(string namespaceUri); } internal interface IXmlNode @@ -312,7 +312,7 @@ namespace Newtonsoft.Json.Converters IXmlNode ParentNode { get; } string Value { get; set; } IXmlNode AppendChild(IXmlNode newChild); - string NamespaceURI { get; } + string NamespaceUri { get; } object WrappedNode { get; } } #endregion @@ -321,12 +321,12 @@ namespace Newtonsoft.Json.Converters #if !NET20 internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration { - internal readonly XDeclaration _declaration; + internal XDeclaration Declaration { get; private set; } public XDeclarationWrapper(XDeclaration declaration) : base(null) { - _declaration = declaration; + Declaration = declaration; } public override XmlNodeType NodeType @@ -336,19 +336,19 @@ namespace Newtonsoft.Json.Converters public string Version { - get { return _declaration.Version; } + get { return Declaration.Version; } } public string Encoding { - get { return _declaration.Encoding; } - set { _declaration.Encoding = value; } + get { return Declaration.Encoding; } + set { Declaration.Encoding = value; } } public string Standalone { - get { return _declaration.Standalone; } - set { _declaration.Standalone = value; } + get { return Declaration.Standalone; } + set { Declaration.Standalone = value; } } } @@ -417,10 +417,10 @@ namespace Newtonsoft.Json.Converters return new XElementWrapper(new XElement(elementName)); } - public IXmlElement CreateElement(string qualifiedName, string namespaceURI) + public IXmlElement CreateElement(string qualifiedName, string namespaceUri) { string localName = MiscellaneousUtils.GetLocalName(qualifiedName); - return new XElementWrapper(new XElement(XName.Get(localName, namespaceURI))); + return new XElementWrapper(new XElement(XName.Get(localName, namespaceUri))); } public IXmlNode CreateAttribute(string name, string value) @@ -428,10 +428,10 @@ namespace Newtonsoft.Json.Converters return new XAttributeWrapper(new XAttribute(name, value)); } - public IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value) + public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value) { string localName = MiscellaneousUtils.GetLocalName(qualifiedName); - return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceURI), value)); + return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value)); } public IXmlElement DocumentElement @@ -450,7 +450,7 @@ namespace Newtonsoft.Json.Converters XDeclarationWrapper declarationWrapper = newChild as XDeclarationWrapper; if (declarationWrapper != null) { - Document.Declaration = declarationWrapper._declaration; + Document.Declaration = declarationWrapper.Declaration; return declarationWrapper; } else @@ -649,7 +649,7 @@ namespace Newtonsoft.Json.Converters throw new InvalidOperationException(); } - public virtual string NamespaceURI + public virtual string NamespaceUri { get { return null; } } @@ -678,7 +678,7 @@ namespace Newtonsoft.Json.Converters get { return Attribute.Name.LocalName; } } - public override string NamespaceURI + public override string NamespaceUri { get { return Attribute.Name.NamespaceName; } } @@ -729,14 +729,14 @@ namespace Newtonsoft.Json.Converters get { return Element.Name.LocalName; } } - public override string NamespaceURI + public override string NamespaceUri { get { return Element.Name.NamespaceName; } } - public string GetPrefixOfNamespace(string namespaceURI) + public string GetPrefixOfNamespace(string namespaceUri) { - return Element.GetPrefixOfNamespace(namespaceURI); + return Element.GetPrefixOfNamespace(namespaceUri); } } #endif @@ -836,7 +836,7 @@ namespace Newtonsoft.Json.Converters manager.PushScope(); foreach (IXmlNode attribute in parentElement.Attributes) { - if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns") + if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns") manager.AddNamespace(attribute.LocalName, attribute.Value); } } @@ -845,9 +845,9 @@ namespace Newtonsoft.Json.Converters private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager) { - string prefix = (node.NamespaceURI == null || (node.LocalName == "xmlns" && node.NamespaceURI == "http://www.w3.org/2000/xmlns/")) + string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/")) ? null - : manager.LookupPrefix(node.NamespaceURI); + : manager.LookupPrefix(node.NamespaceUri); if (!string.IsNullOrEmpty(prefix)) return prefix + ":" + node.LocalName; @@ -860,7 +860,7 @@ namespace Newtonsoft.Json.Converters switch (node.NodeType) { case XmlNodeType.Attribute: - if (node.NamespaceURI == JsonNamespaceUri) + if (node.NamespaceUri == JsonNamespaceUri) return "$" + node.LocalName; else return "@" + ResolveFullName(node, manager); @@ -888,7 +888,7 @@ namespace Newtonsoft.Json.Converters private bool IsArray(IXmlNode node) { IXmlNode jsonArrayAttribute = (node.Attributes != null) - ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceURI == JsonNamespaceUri) + ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceUri == JsonNamespaceUri) : null; return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value)); @@ -970,7 +970,7 @@ namespace Newtonsoft.Json.Converters { foreach (IXmlNode attribute in node.Attributes) { - if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/") + if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/") { string prefix = (attribute.LocalName != "xmlns") ? attribute.LocalName @@ -1020,10 +1020,10 @@ namespace Newtonsoft.Json.Converters case XmlNodeType.ProcessingInstruction: case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: - if (node.NamespaceURI == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri) + if (node.NamespaceUri == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri) return; - if (node.NamespaceURI == JsonNamespaceUri) + if (node.NamespaceUri == JsonNamespaceUri) { if (node.LocalName == "Array") return; @@ -1512,7 +1512,7 @@ namespace Newtonsoft.Json.Converters private IEnumerable ValueAttributes(IEnumerable c) { - return c.Where(a => a.NamespaceURI != JsonNamespaceUri); + return c.Where(a => a.NamespaceUri != JsonNamespaceUri); } #endregion diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 7564d9e3..1963c8e4 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -161,7 +161,7 @@ namespace Newtonsoft.Json // once in the last 10% of the buffer shift the remainling content to the start to avoid // unnessesarly increasing the buffer size when reading numbers/strings int length = _chars.Length; - if (length - _charPos <= length*0.1) + if (length - _charPos <= length * 0.1) { int count = _charsUsed - _charPos; if (count > 0) @@ -403,7 +403,7 @@ namespace Newtonsoft.Json if (TokenType == JsonToken.Null) return null; if (TokenType == JsonToken.Bytes) - return (byte[]) Value; + return (byte[])Value; if (TokenType == JsonToken.StartArray) { List data = new List(); @@ -453,10 +453,10 @@ namespace Newtonsoft.Json if (TokenType == JsonToken.Null) return null; if (TokenType == JsonToken.Float) - return (decimal?) Value; + return (decimal?)Value; decimal d; - if (TokenType == JsonToken.String && decimal.TryParse((string) Value, NumberStyles.Number, Culture, out d)) + if (TokenType == JsonToken.String && decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) { SetToken(JsonToken.Float, d); return d; @@ -486,10 +486,10 @@ namespace Newtonsoft.Json if (TokenType == JsonToken.Null) return null; if (TokenType == JsonToken.Date) - return (DateTimeOffset) Value; + return (DateTimeOffset)Value; DateTimeOffset dt; - if (TokenType == JsonToken.String && DateTimeOffset.TryParse((string) Value, Culture, DateTimeStyles.None, out dt)) + if (TokenType == JsonToken.String && DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt)) { SetToken(JsonToken.Date, dt); return dt; @@ -506,12 +506,6 @@ namespace Newtonsoft.Json { while (true) { - if (_charPos >= _charsUsed) - { - if (!ReadChars(0, false)) - return false; - } - switch (_currentState) { case State.Start: @@ -706,6 +700,58 @@ namespace Newtonsoft.Json } } + private void ReadNumberIntoBuffer() + { + int charPos = _charPos; + + while (true) + { + switch (_chars[charPos++]) + { + case '\0': + if (_charsUsed == charPos - 1) + { + charPos--; + _charPos = charPos; + if (ReadData(true) == 0) + return; + } + break; + case '-': + case '+': + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + case 'x': + case 'X': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + _charPos = charPos - 1; + return; + } + } + } + private void ClearRecentString() { if (_buffer != null) @@ -726,7 +772,10 @@ namespace Newtonsoft.Json if (_charsUsed == _charPos) { if (ReadData(false) == 0) + { + _currentState = State.Finished; return false; + } } else { @@ -890,7 +939,7 @@ namespace Newtonsoft.Json { if (ReadData(true) == 0) throw CreateJsonReaderException("Unexpected end when parsing unquoted property name. Line {0}, position {1}.", LineNumber, LinePosition); - + break; } @@ -909,7 +958,7 @@ namespace Newtonsoft.Json _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); return; } - + throw CreateJsonReaderException("Invalid JavaScript property identifier character: {0}. Line {1}, position {2}.", currentChar, LineNumber, LinePosition); } } @@ -1173,32 +1222,7 @@ namespace Newtonsoft.Json char firstChar = _chars[_charPos]; int initialPosition = _charPos; - // parse until seperator character or end - while (true) - { - char currentChar = _chars[_charPos]; - - if (currentChar == '\0') - { - if (_charsUsed == _charPos) - { - if (ReadData(true) == 0) - break; - } - else - { - _charPos++; - } - } - else if (IsSeperator(currentChar)) - { - break; - } - else - { - _charPos++; - } - } + ReadNumberIntoBuffer(); _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); @@ -1240,7 +1264,7 @@ namespace Newtonsoft.Json if (singleDigit) { // digit char values start at 48 - numberValue = (long) firstChar - 48; + numberValue = (long)firstChar - 48; numberType = JsonToken.Integer; } else if (nonBase10) @@ -1531,7 +1555,7 @@ namespace Newtonsoft.Json { if (CurrentState == State.Start && LinePosition == 0) return 0; - + return _lineNumber; } } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 0eb68379..fb430bf1 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using System.IO; using System.Xml; @@ -91,7 +92,7 @@ namespace Newtonsoft.Json /// public abstract class JsonWriter : IDisposable { - private enum State + internal enum State { Start, Property, @@ -107,19 +108,58 @@ namespace Newtonsoft.Json } // array that gives a new state based on the current state an the token being written - private static readonly State[][] stateArray = new[] { -// Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error + private static readonly State[][] StateArray; + + internal static readonly State[][] StateArrayTempate = new[] { +// Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error // -/* None */new[]{ State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error }, -/* StartObject */new[]{ State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.Error, State.Error }, -/* StartArray */new[]{ State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.Error, State.Error }, -/* StartConstructor */new[]{ State.ConstructorStart, State.ConstructorStart, State.Error, State.Error, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error, State.Error }, -/* StartProperty */new[]{ State.Property, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error }, -/* Comment */new[]{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }, -/* Raw */new[]{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }, -/* Value */new[]{ State.Start, State.Object, State.Error, State.Error, State.Array, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }, +/* None */new[]{ State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error }, +/* StartObject */new[]{ State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.Error, State.Error }, +/* StartArray */new[]{ State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.Error, State.Error }, +/* StartConstructor */new[]{ State.ConstructorStart, State.ConstructorStart, State.Error, State.Error, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error, State.Error }, +/* StartProperty */new[]{ State.Property, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error }, +/* Comment */new[]{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }, +/* Raw */new[]{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }, +/* Value (this will be copied) */new[]{ State.Start, State.Object, State.Error, State.Error, State.Array, State.Array, State.Constructor, State.Constructor, State.Error, State.Error } }; + internal static State[][] BuildStateArray() + { + var allStates = StateArrayTempate.ToList(); + var errorStates = StateArrayTempate[0]; + var valueStates = StateArrayTempate[7]; + + foreach (JsonToken valueToken in EnumUtils.GetValues(typeof(JsonToken))) + { + if (allStates.Count <= (int)valueToken) + { + switch (valueToken) + { + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.String: + case JsonToken.Boolean: + case JsonToken.Null: + case JsonToken.Undefined: + case JsonToken.Date: + case JsonToken.Bytes: + allStates.Add(valueStates); + break; + default: + allStates.Add(errorStates); + break; + } + } + } + + return allStates.ToArray(); + } + + static JsonWriter() + { + StateArray = BuildStateArray(); + } + private int _top; private readonly List _stack; @@ -583,31 +623,11 @@ namespace Newtonsoft.Json internal void AutoComplete(JsonToken tokenBeingWritten) { - int token; - - switch (tokenBeingWritten) - { - default: - token = (int)tokenBeingWritten; - break; - case JsonToken.Integer: - case JsonToken.Float: - case JsonToken.String: - case JsonToken.Boolean: - case JsonToken.Null: - case JsonToken.Undefined: - case JsonToken.Date: - case JsonToken.Bytes: - // a value is being written - token = 7; - break; - } - // gets new state based on the current state and what is being written - State newState = stateArray[token][(int)_currentState]; + State newState = StateArray[(int)tokenBeingWritten][(int)_currentState]; if (newState == State.Error) - throw new JsonWriterException("Token {0} in state {1} would result in an invalid JavaScript object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString())); + throw new JsonWriterException("Token {0} in state {1} would result in an invalid JSON object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString())); if ((_currentState == State.Object || _currentState == State.Array || _currentState == State.Constructor) && tokenBeingWritten != JsonToken.Comment) { diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs index ba3c7505..f126b9aa 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs @@ -157,12 +157,12 @@ namespace Newtonsoft.Json.Schema model.PatternProperties[property.Key] = BuildNodeModel(property.Value); } - for (int i = 0; i < node.Items.Count; i++) + foreach (JsonSchemaNode t in node.Items) { if (model.Items == null) model.Items = new List(); - model.Items.Add(BuildNodeModel(node.Items[i])); + model.Items.Add(BuildNodeModel(t)); } if (node.AdditionalProperties != null) model.AdditionalProperties = BuildNodeModel(node.AdditionalProperties); diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index b3a5fb27..6e2a474d 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -594,7 +594,7 @@ namespace Newtonsoft.Json.Serialization JsonISerializableContract contract = new JsonISerializableContract(objectType); InitializeContract(contract); - ConstructorInfo constructorInfo = objectType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(SerializationInfo), typeof(StreamingContext) }, null); + ConstructorInfo constructorInfo = contract.NonNullableUnderlyingType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(SerializationInfo), typeof(StreamingContext) }, null); if (constructorInfo != null) { MethodCall methodCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(constructorInfo); @@ -647,37 +647,37 @@ namespace Newtonsoft.Json.Serialization Type t = ReflectionUtils.EnsureNotNullableType(objectType); if (JsonConvert.IsJsonPrimitiveType(t)) - return CreatePrimitiveContract(t); + return CreatePrimitiveContract(objectType); if (JsonTypeReflector.GetJsonObjectAttribute(t) != null) - return CreateObjectContract(t); + return CreateObjectContract(objectType); if (JsonTypeReflector.GetJsonArrayAttribute(t) != null) - return CreateArrayContract(t); + return CreateArrayContract(objectType); if (t == typeof(JToken) || t.IsSubclassOf(typeof(JToken))) - return CreateLinqContract(t); + return CreateLinqContract(objectType); if (CollectionUtils.IsDictionaryType(t)) - return CreateDictionaryContract(t); + return CreateDictionaryContract(objectType); if (typeof(IEnumerable).IsAssignableFrom(t)) - return CreateArrayContract(t); + return CreateArrayContract(objectType); if (CanConvertToString(t)) - return CreateStringContract(t); + return CreateStringContract(objectType); #if !SILVERLIGHT && !PocketPC if (typeof(ISerializable).IsAssignableFrom(t)) - return CreateISerializableContract(t); + return CreateISerializableContract(objectType); #endif #if !(NET35 || NET20 || WINDOWS_PHONE) if (typeof(IDynamicMetaObjectProvider).IsAssignableFrom(t)) - return CreateDynamicContract(t); + return CreateDynamicContract(objectType); #endif - return CreateObjectContract(t); + return CreateObjectContract(objectType); } internal static bool CanConvertToString(Type type) diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs index 857e5352..f8b1a4ea 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs @@ -35,6 +35,16 @@ namespace Newtonsoft.Json.Serialization /// public abstract class JsonContract { + internal enum ReadType + { + Read, + ReadAsDecimal, + ReadAsBytes, +#if !NET20 + ReadAsDateTimeOffset +#endif + } + /// /// Gets the underlying type for the contract. /// @@ -63,22 +73,30 @@ namespace Newtonsoft.Json.Serialization // checked for after passed in converters and attribute specified converters internal JsonConverter InternalConverter { get; set; } + internal ReadType InternalReadType; + internal bool IsNullable; + internal bool IsConvertable; + internal Type NonNullableUnderlyingType; + #if !PocketPC /// /// Gets or sets the method called immediately after deserialization of the object. /// /// The method called immediately after deserialization of the object. public MethodInfo OnDeserialized { get; set; } + /// /// Gets or sets the method called during deserialization of the object. /// /// The method called during deserialization of the object. public MethodInfo OnDeserializing { get; set; } + /// /// Gets or sets the method called after serialization of the object graph. /// /// The method called after serialization of the object graph. public MethodInfo OnSerialized { get; set; } + /// /// Gets or sets the method called before serialization of the object. /// @@ -108,7 +126,7 @@ namespace Newtonsoft.Json.Serialization { #if !PocketPC if (OnSerializing != null) - OnSerializing.Invoke(o, new object[] { context }); + OnSerializing.Invoke(o, new object[] {context}); #endif } @@ -116,7 +134,7 @@ namespace Newtonsoft.Json.Serialization { #if !PocketPC if (OnSerialized != null) - OnSerialized.Invoke(o, new object[] { context }); + OnSerialized.Invoke(o, new object[] {context}); #endif } @@ -124,7 +142,7 @@ namespace Newtonsoft.Json.Serialization { #if !PocketPC if (OnDeserializing != null) - OnDeserializing.Invoke(o, new object[] { context }); + OnDeserializing.Invoke(o, new object[] {context}); #endif } @@ -132,14 +150,14 @@ namespace Newtonsoft.Json.Serialization { #if !PocketPC if (OnDeserialized != null) - OnDeserialized.Invoke(o, new object[] { context }); + OnDeserialized.Invoke(o, new object[] {context}); #endif } internal void InvokeOnError(object o, StreamingContext context, ErrorContext errorContext) { if (OnError != null) - OnError.Invoke(o, new object[] { context, errorContext }); + OnError.Invoke(o, new object[] {context, errorContext}); } internal JsonContract(Type underlyingType) @@ -148,6 +166,31 @@ namespace Newtonsoft.Json.Serialization UnderlyingType = underlyingType; CreatedType = underlyingType; + + IsNullable = ReflectionUtils.IsNullable(underlyingType); + + NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType; + + IsConvertable = typeof(IConvertible).IsAssignableFrom(NonNullableUnderlyingType); + + if (NonNullableUnderlyingType == typeof(byte[])) + { + InternalReadType = ReadType.ReadAsBytes; + } + else if (NonNullableUnderlyingType == typeof(decimal)) + { + InternalReadType = ReadType.ReadAsDecimal; + } +#if !NET20 + else if (NonNullableUnderlyingType == typeof(DateTimeOffset)) + { + InternalReadType = ReadType.ReadAsDateTimeOffset; + } +#endif + else + { + InternalReadType = ReadType.Read; + } } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs index 45a83b3f..16c67fe7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs @@ -45,6 +45,7 @@ namespace Newtonsoft.Json.Serialization internal Type DictionaryKeyType { get; private set; } internal Type DictionaryValueType { get; private set; } + internal JsonContract DictionaryKeyContract { get; set; } internal JsonContract DictionaryValueContract { get; set; } private readonly bool _isDictionaryValueTypeNullableType; diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs index f455636f..761fa76b 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs @@ -55,7 +55,7 @@ namespace Newtonsoft.Json.Serialization private ErrorContext _currentErrorContext; private BidirectionalDictionary _mappings; - internal JsonSerializer Serializer { get; private set; } + internal readonly JsonSerializer Serializer; protected JsonSerializerInternalBase(JsonSerializer serializer) { diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index a393f799..bb77dda7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -241,19 +241,17 @@ namespace Newtonsoft.Json.Serialization case JsonToken.Boolean: case JsonToken.Date: case JsonToken.Bytes: - return EnsureType(reader.Value, CultureInfo.InvariantCulture, objectType); + return EnsureType(reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.String: // convert empty string to null automatically for nullable types - if (string.IsNullOrEmpty((string) reader.Value) && - objectType != null && - ReflectionUtils.IsNullableType(objectType)) + if (string.IsNullOrEmpty((string) reader.Value) && objectType != typeof(string) && contract.IsNullable) return null; // string that needs to be returned as a byte array should be base 64 decoded if (objectType == typeof (byte[])) return Convert.FromBase64String((string) reader.Value); - return EnsureType(reader.Value, CultureInfo.InvariantCulture, objectType); + return EnsureType(reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.StartConstructor: case JsonToken.EndConstructor: string constructorName = reader.Value.ToString(); @@ -264,7 +262,7 @@ namespace Newtonsoft.Json.Serialization if (objectType == typeof (DBNull)) return DBNull.Value; - return EnsureType(reader.Value, CultureInfo.InvariantCulture, objectType); + return EnsureType(reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.Raw: return new JRaw((string) reader.Value); case JsonToken.Comment: @@ -310,90 +308,97 @@ namespace Newtonsoft.Json.Serialization if (reader.TokenType == JsonToken.PropertyName) { - bool specialProperty; + string propertyName = reader.Value.ToString(); - do + if (propertyName.Length > 0 && propertyName[0] == '$') { - string propertyName = reader.Value.ToString(); + // read 'special' properties + // $type, $id, $ref, etc + bool specialProperty; - if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal)) + do { - CheckedRead(reader); - if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null) - throw new JsonSerializationException("JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); + propertyName = reader.Value.ToString(); - string reference = (reader.Value != null) ? reader.Value.ToString() : null; - - CheckedRead(reader); - - if (reference != null) + if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal)) { - if (reader.TokenType == JsonToken.PropertyName) - throw new JsonSerializationException("Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); + CheckedRead(reader); + if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null) + throw new JsonSerializationException("JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); - return Serializer.ReferenceResolver.ResolveReference(this, reference); + string reference = (reader.Value != null) ? reader.Value.ToString() : null; + + CheckedRead(reader); + + if (reference != null) + { + if (reader.TokenType == JsonToken.PropertyName) + throw new JsonSerializationException("Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); + + return Serializer.ReferenceResolver.ResolveReference(this, reference); + } + else + { + specialProperty = true; + } + } + else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal)) + { + CheckedRead(reader); + string qualifiedTypeName = reader.Value.ToString(); + + CheckedRead(reader); + + if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) != TypeNameHandling.None) + { + string typeName; + string assemblyName; + ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName); + + Type specifiedType; + try + { + specifiedType = Serializer.Binder.BindToType(assemblyName, typeName); + } + catch (Exception ex) + { + throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex); + } + + if (specifiedType == null) + throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName)); + + if (objectType != null && !objectType.IsAssignableFrom(specifiedType)) + throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName)); + + objectType = specifiedType; + contract = GetContractSafe(specifiedType); + } + specialProperty = true; + } + else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) + { + CheckedRead(reader); + + id = (reader.Value != null) ? reader.Value.ToString() : null; + + CheckedRead(reader); + specialProperty = true; + } + else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) + { + CheckedRead(reader); + object list = CreateList(reader, objectType, contract, member, existingValue, id); + CheckedRead(reader); + return list; } else { - specialProperty = true; + specialProperty = false; } - } - else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal)) - { - CheckedRead(reader); - string qualifiedTypeName = reader.Value.ToString(); - - CheckedRead(reader); - - if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) != TypeNameHandling.None) - { - string typeName; - string assemblyName; - ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName); - - Type specifiedType; - try - { - specifiedType = Serializer.Binder.BindToType(assemblyName, typeName); - } - catch (Exception ex) - { - throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex); - } - - if (specifiedType == null) - throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName)); - - if (objectType != null && !objectType.IsAssignableFrom(specifiedType)) - throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName)); - - objectType = specifiedType; - contract = GetContractSafe(specifiedType); - } - specialProperty = true; - } - else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) - { - CheckedRead(reader); - - id = (reader.Value != null) ? reader.Value.ToString() : null; - - CheckedRead(reader); - specialProperty = true; - } - else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) - { - CheckedRead(reader); - object list = CreateList(reader, objectType, contract, member, existingValue, id); - CheckedRead(reader); - return list; - } - else - { - specialProperty = false; - } - } while (specialProperty - && reader.TokenType == JsonToken.PropertyName); + } while (specialProperty + && reader.TokenType == JsonToken.PropertyName); + } } if (!HasDefinedType(objectType)) @@ -499,7 +504,7 @@ namespace Newtonsoft.Json.Serialization ); } - private object EnsureType(object value, CultureInfo culture, Type targetType) + private object EnsureType(object value, CultureInfo culture, JsonContract contract, Type targetType) { if (targetType == null) return value; @@ -512,6 +517,22 @@ namespace Newtonsoft.Json.Serialization { try { + if (value == null && contract.IsNullable) + return null; + + if (contract.IsConvertable) + { + if (targetType.IsEnum) + { + if (value is string) + return Enum.Parse(targetType, value.ToString(), true); + else if (ConvertUtils.IsInteger(value)) + return Enum.ToObject(targetType, value); + } + + return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture); + } + return ConvertUtils.ConvertOrCast(value, culture, targetType); } catch (Exception ex) @@ -654,9 +675,12 @@ namespace Newtonsoft.Json.Serialization object keyValue = reader.Value; try { + if (contract.DictionaryKeyContract == null) + contract.DictionaryKeyContract = GetContractSafe(contract.DictionaryKeyType); + try { - keyValue = EnsureType(keyValue, CultureInfo.InvariantCulture, contract.DictionaryKeyType); + keyValue = EnsureType(keyValue, CultureInfo.InvariantCulture, contract.DictionaryKeyContract, contract.DictionaryKeyType); } catch (Exception ex) { @@ -1069,47 +1093,46 @@ namespace Newtonsoft.Json.Serialization private bool ReadForType(JsonReader reader, JsonContract contract, bool hasConverter, bool inArray) { - Type t = (contract != null) ? contract.UnderlyingType : null; - // don't read properties with converters as a specific value // the value might be a string which will then get converted which will error if read as date for example if (hasConverter) return reader.Read(); - if (t == typeof (byte[])) - { - SetSerializeInArray(reader, inArray, true); - reader.ReadAsBytes(); - SetSerializeInArray(reader, inArray, false); + JsonContract.ReadType t = (contract != null) ? contract.InternalReadType : JsonContract.ReadType.Read; - return true; - } - else if ((t == typeof (decimal) || t == typeof (decimal?))) + switch (t) { - SetSerializeInArray(reader, inArray, true); - reader.ReadAsDecimal(); - SetSerializeInArray(reader, inArray, false); + case JsonContract.ReadType.Read: + do + { + if (!reader.Read()) + return false; + } while (reader.TokenType == JsonToken.Comment); - return true; - } + return true; + case JsonContract.ReadType.ReadAsDecimal: + SetSerializeInArray(reader, inArray, true); + reader.ReadAsDecimal(); + SetSerializeInArray(reader, inArray, false); + + return true; + case JsonContract.ReadType.ReadAsBytes: + SetSerializeInArray(reader, inArray, true); + reader.ReadAsBytes(); + SetSerializeInArray(reader, inArray, false); + + return true; #if !NET20 - else if ((t == typeof (DateTimeOffset) || t == typeof (DateTimeOffset?))) - { - SetSerializeInArray(reader, inArray, true); - reader.ReadAsDateTimeOffset(); - SetSerializeInArray(reader, inArray, false); + case JsonContract.ReadType.ReadAsDateTimeOffset: + SetSerializeInArray(reader, inArray, true); + reader.ReadAsDateTimeOffset(); + SetSerializeInArray(reader, inArray, false); - return true; - } + return true; #endif - - do - { - if (!reader.Read()) - return false; - } while (reader.TokenType == JsonToken.Comment); - - return true; + default: + throw new ArgumentOutOfRangeException(); + } } private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, string id) @@ -1178,9 +1201,12 @@ namespace Newtonsoft.Json.Serialization if (property.Required == Required.AllowNull || property.Required == Required.Always) throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); + if (property.PropertyContract == null) + property.PropertyContract = GetContractSafe(property.PropertyType); + if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Populate) && property.Writable) - property.ValueProvider.SetValue(newObject, EnsureType(property.DefaultValue, CultureInfo.InvariantCulture, property.PropertyType)); + property.ValueProvider.SetValue(newObject, EnsureType(property.DefaultValue, CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType)); break; case PropertyPresence.Null: if (property.Required == Required.Always) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index e0d87987..5ac8dcd4 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -43,19 +43,8 @@ namespace Newtonsoft.Json.Serialization { internal class JsonSerializerInternalWriter : JsonSerializerInternalBase { + private readonly List _serializeStack = new List(); private JsonSerializerProxy _internalSerializer; - private List _serializeStack; - - private List SerializeStack - { - get - { - if (_serializeStack == null) - _serializeStack = new List(); - - return _serializeStack; - } - } public JsonSerializerInternalWriter(JsonSerializer serializer) : base(serializer) @@ -228,7 +217,7 @@ namespace Newtonsoft.Json.Serialization if (value == null || contract is JsonPrimitiveContract) return true; - if (SerializeStack.IndexOf(value) != -1) + if (_serializeStack.IndexOf(value) != -1) { switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling)) { @@ -311,7 +300,7 @@ namespace Newtonsoft.Json.Serialization { contract.InvokeOnSerializing(value, Serializer.Context); - SerializeStack.Add(value); + _serializeStack.Add(value); writer.WriteStartObject(); bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); @@ -352,7 +341,7 @@ namespace Newtonsoft.Json.Serialization } writer.WriteEndObject(); - SerializeStack.RemoveAt(SerializeStack.Count - 1); + _serializeStack.RemoveAt(_serializeStack.Count - 1); contract.InvokeOnSerialized(value, Serializer.Context); } @@ -389,11 +378,11 @@ namespace Newtonsoft.Json.Serialization if (!CheckForCircularReference(value, null, contract)) return; - SerializeStack.Add(value); + _serializeStack.Add(value); converter.WriteJson(writer, value, GetInternalSerializer()); - SerializeStack.RemoveAt(SerializeStack.Count - 1); + _serializeStack.RemoveAt(_serializeStack.Count - 1); } } @@ -401,7 +390,7 @@ namespace Newtonsoft.Json.Serialization { contract.InvokeOnSerializing(values.UnderlyingCollection, Serializer.Context); - SerializeStack.Add(values.UnderlyingCollection); + _serializeStack.Add(values.UnderlyingCollection); bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays); bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, collectionValueContract); @@ -471,7 +460,7 @@ namespace Newtonsoft.Json.Serialization writer.WriteEndObject(); } - SerializeStack.RemoveAt(SerializeStack.Count - 1); + _serializeStack.RemoveAt(_serializeStack.Count - 1); contract.InvokeOnSerialized(values.UnderlyingCollection, Serializer.Context); } @@ -484,7 +473,7 @@ namespace Newtonsoft.Json.Serialization private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContract collectionValueContract) { contract.InvokeOnSerializing(value, Serializer.Context); - SerializeStack.Add(value); + _serializeStack.Add(value); writer.WriteStartObject(); @@ -504,7 +493,7 @@ namespace Newtonsoft.Json.Serialization writer.WriteEndObject(); - SerializeStack.RemoveAt(SerializeStack.Count - 1); + _serializeStack.RemoveAt(_serializeStack.Count - 1); contract.InvokeOnSerialized(value, Serializer.Context); } #endif @@ -519,7 +508,7 @@ namespace Newtonsoft.Json.Serialization private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract) { contract.InvokeOnSerializing(value, Serializer.Context); - SerializeStack.Add(value); + _serializeStack.Add(value); writer.WriteStartObject(); @@ -539,7 +528,7 @@ namespace Newtonsoft.Json.Serialization writer.WriteEndObject(); - SerializeStack.RemoveAt(SerializeStack.Count - 1); + _serializeStack.RemoveAt(_serializeStack.Count - 1); contract.InvokeOnSerialized(value, Serializer.Context); } #endif @@ -574,7 +563,7 @@ namespace Newtonsoft.Json.Serialization { contract.InvokeOnSerializing(values.UnderlyingDictionary, Serializer.Context); - SerializeStack.Add(values.UnderlyingDictionary); + _serializeStack.Add(values.UnderlyingDictionary); writer.WriteStartObject(); bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); @@ -636,7 +625,7 @@ namespace Newtonsoft.Json.Serialization } writer.WriteEndObject(); - SerializeStack.RemoveAt(SerializeStack.Count - 1); + _serializeStack.RemoveAt(_serializeStack.Count - 1); contract.InvokeOnSerialized(values.UnderlyingDictionary, Serializer.Context); } diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs index 45dc8c37..e3b3d9d4 100644 --- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs @@ -118,12 +118,6 @@ namespace Newtonsoft.Json.Utilities if (targetType == initialType) return initialValue; - if (initialValue is string && typeof(Type).IsAssignableFrom(targetType)) - return Type.GetType((string) initialValue, true); - - if (targetType.IsInterface || targetType.IsGenericTypeDefinition || targetType.IsAbstract) - throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType"); - // use Convert.ChangeType if both types are IConvertible if (initialValue is IConvertible && typeof(IConvertible).IsAssignableFrom(targetType)) { @@ -134,10 +128,16 @@ namespace Newtonsoft.Json.Utilities else if (IsInteger(initialValue)) return Enum.ToObject(targetType, initialValue); } - + return System.Convert.ChangeType(initialValue, targetType, culture); } + if (initialValue is string && typeof(Type).IsAssignableFrom(targetType)) + return Type.GetType((string) initialValue, true); + + if (targetType.IsInterface || targetType.IsGenericTypeDefinition || targetType.IsAbstract) + throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType"); + #if !PocketPC && !NET20 if (initialValue is DateTime && targetType == typeof(DateTimeOffset)) return new DateTimeOffset((DateTime)initialValue); diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs index 347474a1..bd610269 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs @@ -224,19 +224,19 @@ namespace Newtonsoft.Json.Utilities callArgs.AddRange(args); callArgs.Add(result); - DynamicMetaObject resultMO = new DynamicMetaObject(result, BindingRestrictions.Empty); + DynamicMetaObject resultMetaObject = new DynamicMetaObject(result, BindingRestrictions.Empty); // Need to add a conversion if calling TryConvert if (binder.ReturnType != typeof (object)) { - UnaryExpression convert = Expression.Convert(resultMO.Expression, binder.ReturnType); + UnaryExpression convert = Expression.Convert(resultMetaObject.Expression, binder.ReturnType); // will always be a cast or unbox - resultMO = new DynamicMetaObject(convert, resultMO.Restrictions); + resultMetaObject = new DynamicMetaObject(convert, resultMetaObject.Restrictions); } if (fallbackInvoke != null) - resultMO = fallbackInvoke(resultMO); + resultMetaObject = fallbackInvoke(resultMetaObject); DynamicMetaObject callDynamic = new DynamicMetaObject( Expression.Block( @@ -247,12 +247,12 @@ namespace Newtonsoft.Json.Utilities typeof(DynamicProxy).GetMethod(methodName), callArgs ), - resultMO.Expression, + resultMetaObject.Expression, fallbackResult.Expression, binder.ReturnType ) ), - GetRestrictions().Merge(resultMO.Restrictions).Merge(fallbackResult.Restrictions) + GetRestrictions().Merge(resultMetaObject.Restrictions).Merge(fallbackResult.Restrictions) ); return callDynamic; diff --git a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs index c36020ce..7c9222b7 100644 --- a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs @@ -51,7 +51,7 @@ namespace Newtonsoft.Json.Utilities var c = s[i]; // don't escape standard text/numbers except '\' and the text delimiter - if (c >= ' ' && c < 128 && c != '\\' && c != '\'' && c != '"') + if (c >= ' ' && c < 128 && c != '\\' && c != delimiter) continue; string escapedValue; @@ -86,12 +86,12 @@ namespace Newtonsoft.Json.Utilities escapedValue = @"\u2029"; break; case '\'': - // only escape if this charater is being used as the delimiter - escapedValue = (delimiter == '\'') ? @"\'" : null; + // this charater is being used as the delimiter + escapedValue = @"\'"; break; case '"': - // only escape if this charater is being used as the delimiter - escapedValue = (delimiter == '"') ? "\\\"" : null; + // this charater is being used as the delimiter + escapedValue = "\\\""; break; default: escapedValue = (c <= '\u001f') ? StringUtils.ToCharAsUnicode(c) : null; diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 0a904ddf..be3f467c 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -202,21 +202,6 @@ namespace Newtonsoft.Json.Utilities : t; } - public static object CreateUnitializedValue(Type type) - { - ValidationUtils.ArgumentNotNull(type, "type"); - - if (type.IsGenericTypeDefinition) - throw new ArgumentException("Type {0} is a generic type definition and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, type), "type"); - - if (type.IsClass || type.IsInterface || type == typeof(void)) - return null; - else if (type.IsValueType) - return Activator.CreateInstance(type); - else - throw new ArgumentException("Type {0} cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, type), "type"); - } - public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition) { Type implementingType; diff --git a/Src/Newtonsoft.Json/Utilities/StringBuffer.cs b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs index 321caa40..840540b5 100644 --- a/Src/Newtonsoft.Json/Utilities/StringBuffer.cs +++ b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs @@ -35,7 +35,7 @@ namespace Newtonsoft.Json.Utilities private char[] _buffer; private int _position; - private static readonly char[] _emptyBuffer = new char[0]; + private static readonly char[] EmptyBuffer = new char[0]; public int Position { @@ -45,7 +45,7 @@ namespace Newtonsoft.Json.Utilities public StringBuffer() { - _buffer = _emptyBuffer; + _buffer = EmptyBuffer; } public StringBuffer(int initalSize) @@ -75,7 +75,7 @@ namespace Newtonsoft.Json.Utilities public void Clear() { - _buffer = _emptyBuffer; + _buffer = EmptyBuffer; _position = 0; }