diff --git a/Src/Newtonsoft.Json.Tests/JsonRawTests.cs b/Src/Newtonsoft.Json.Tests/JsonRawTests.cs deleted file mode 100644 index e2ae30ec..00000000 --- a/Src/Newtonsoft.Json.Tests/JsonRawTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; - -namespace Newtonsoft.Json.Tests -{ - public class JsonRawTests : TestFixtureBase - { - [Test] - public void Create() - { - JsonRaw raw = new JsonRaw("Test"); - Assert.AreEqual("Test", raw.Content); - Assert.AreEqual("Test", raw.ToString()); - } - - [Test] - public void EqualsShouldEqualOnSameContent() - { - JsonRaw r1 = new JsonRaw("Test"); - JsonRaw r2 = new JsonRaw("Test"); - - Assert.AreEqual(r1, r2); - Assert.AreNotEqual(r1, null); - Assert.IsFalse(r1.Equals(null)); - } - - [Test] - public void GetHashCodeShouldEqualOnSameContent() - { - JsonRaw r1 = new JsonRaw("Test"); - JsonRaw r2 = new JsonRaw("Test"); - JsonRaw r3 = new JsonRaw("Test1"); - - Assert.AreEqual(r1.GetHashCode(), r2.GetHashCode()); - Assert.AreNotEqual(r1.GetHashCode(), r3.GetHashCode()); - } - } -} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs index df01bbdd..014c00cf 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs @@ -243,7 +243,7 @@ Parameter name: arrayIndex")] PersonRaw raw = new PersonRaw { FirstName = "FirstNameValue", - RawContent = new JsonRaw("[1,2,3,4,5]"), + RawContent = new JRaw("[1,2,3,4,5]"), LastName = "LastNameValue" }; @@ -261,7 +261,7 @@ Parameter name: arrayIndex")] PersonRaw raw = new PersonRaw { FirstName = "FirstNameValue", - RawContent = new JsonRaw("[1,2,3,4,5]"), + RawContent = new JRaw("[1,2,3,4,5]"), LastName = "LastNameValue" }; @@ -302,7 +302,7 @@ Parameter name: arrayIndex")] PersonRaw raw = new PersonRaw { FirstName = "FirstNameValue", - RawContent = new JsonRaw("[1,2,3,4,5]"), + RawContent = new JRaw("[1,2,3,4,5]"), LastName = "LastNameValue" }; @@ -314,7 +314,7 @@ Parameter name: arrayIndex")] Assert.AreEqual("FirstNameValue", raw.FirstName); Assert.AreEqual("LastNameValue", raw.LastName); - Assert.AreEqual("[1,2,3,4,5]", raw.RawContent.Content); + Assert.AreEqual("[1,2,3,4,5]", raw.RawContent.Value); } [Test] @@ -366,8 +366,8 @@ Parameter name: arrayIndex")] public void RawChildValues() { JObject o = new JObject(); - o["val1"] = JValue.CreateRaw("1"); - o["val2"] = JValue.CreateRaw("1"); + o["val1"] = new JRaw("1"); + o["val2"] = new JRaw("1"); string json = o.ToString(); diff --git a/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs new file mode 100644 index 00000000..8013ad17 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Linq +{ + public class JRawTests : TestFixtureBase + { + [Test] + public void RawEquals() + { + JRaw r1 = new JRaw("raw1"); + JRaw r2 = new JRaw("raw1"); + JRaw r3 = new JRaw("raw2"); + + Assert.IsTrue(JToken.DeepEquals(r1, r2)); + Assert.IsFalse(JToken.DeepEquals(r1, r3)); + } + + [Test] + public void RawClone() + { + JRaw r1 = new JRaw("raw1"); + JToken r2 = r1.CloneToken(); + + Assert.IsInstanceOfType(typeof(JRaw), r2); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj index 090b1369..06566591 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj @@ -68,6 +68,7 @@ + @@ -87,10 +88,14 @@ + + + + @@ -102,6 +107,7 @@ + @@ -115,16 +121,19 @@ + + + @@ -134,6 +143,7 @@ + @@ -159,7 +169,6 @@ - @@ -177,12 +186,14 @@ + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj index 661e7e57..6a6bbf6f 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj @@ -75,6 +75,7 @@ + @@ -165,7 +166,6 @@ - diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index 0e158db7..86cd963c 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -79,6 +79,7 @@ + @@ -98,10 +99,14 @@ + + + + @@ -113,6 +118,7 @@ + @@ -126,16 +132,19 @@ + + + @@ -145,6 +154,7 @@ + @@ -170,7 +180,6 @@ - @@ -188,12 +197,14 @@ + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 89fe8467..588a99a9 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -114,15 +114,21 @@ + + + + + + @@ -149,6 +155,9 @@ + + + @@ -209,7 +218,6 @@ - diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs index e01f4994..5c1cd929 100644 --- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs @@ -16,13 +16,10 @@ using Newtonsoft.Json.Bson; namespace Newtonsoft.Json.Tests { - /// - /// Summary description for JsonSerializerTest - /// public class PerformanceTests : TestFixtureBase { - private int Iterations = 100; - //private int Iterations = 5000; + private const int Iterations = 100; + //private const int Iterations = 5000; private const string BsonHex = @"B4-01-00-00-04-73-74-72-69-6E-67-73-00-44-00-00-00-02-30-00-05-00-00-00-52-69-63-6B-00-02-31-00-17-00-00-00-4D-61-72-6B-75-73-20-65-67-67-65-72-20-5D-5B-2C-20-28-32-6E-64-29-00-02-32-00-0E-00-00-00-4B-65-76-69-6E-20-4D-63-4E-65-69-73-68-00-00-03-64-69-63-74-69-6F-6E-61-72-79-00-27-00-00-00-10-56-61-6C-20-61-73-64-31-00-01-00-00-00-10-56-61-6C-32-00-03-00-00-00-10-56-61-6C-33-00-04-00-00-00-00-02-4E-61-6D-65-00-05-00-00-00-52-69-63-6B-00-09-4E-6F-77-00-A0-80-DB-70-25-01-00-00-01-42-69-67-4E-75-6D-62-65-72-00-E7-7B-CC-26-96-C7-1F-42-03-41-64-64-72-65-73-73-31-00-48-00-00-00-02-41-64-64-72-65-73-73-00-0B-00-00-00-66-66-66-20-53-74-72-65-65-74-00-02-50-68-6F-6E-65-00-0F-00-00-00-28-35-30-33-29-20-38-31-34-2D-36-33-33-35-00-09-45-6E-74-65-72-65-64-00-20-C2-A3-D7-25-01-00-00-00-04-41-64-64-72-65-73-73-65-73-00-A3-00-00-00-03-30-00-4B-00-00-00-02-41-64-64-72-65-73-73-00-0E-00-00-00-61-72-72-61-79-20-61-64-64-72-65-73-73-00-02-50-68-6F-6E-65-00-0F-00-00-00-28-35-30-33-29-20-38-31-34-2D-36-33-33-35-00-09-45-6E-74-65-72-65-64-00-20-36-7E-6B-25-01-00-00-00-03-31-00-4D-00-00-00-02-41-64-64-72-65-73-73-00-10-00-00-00-61-72-72-61-79-20-32-20-61-64-64-72-65-73-73-00-02-50-68-6F-6E-65-00-0F-00-00-00-28-35-30-33-29-20-38-31-34-2D-36-33-33-35-00-09-45-6E-74-65-72-65-64-00-20-DA-57-66-25-01-00-00-00-00-00"; @@ -71,6 +68,44 @@ namespace Newtonsoft.Json.Tests private DateTime BaseDate = DateTime.Parse("01/01/2000"); + [Test] + public void Serialize() + { + TestClass test = new TestClass(); + + test.Address1.Address = "fff Street"; + test.Address1.Entered = DateTime.Now.AddDays(20); + + test.BigNumber = 34123123123.121M; + test.Now = DateTime.Now.AddHours(1); + test.strings = new List() { "Rick", "Markus egger ][, (2nd)", "Kevin McNeish" }; + + cAddress address = new cAddress(); + address.Entered = DateTime.Now.AddDays(-1); + address.Address = "array address"; + + test.Addresses.Add(address); + + address = new cAddress(); + address.Entered = DateTime.Now.AddDays(-2); + address.Address = "array 2 address"; + test.Addresses.Add(address); + + BenchmarkSerializeMethod(SerializeMethod.JsonNet, test); + BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, test); + BenchmarkSerializeMethod(SerializeMethod.JavaScriptSerializer, test); + BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, test); + } + + [Test] + public void Deserialize() + { + BenchmarkDeserializeMethod(SerializeMethod.JsonNet, JsonText); + BenchmarkDeserializeMethod(SerializeMethod.JsonNetBinary, MiscellaneousUtils.HexToBytes(BsonHex)); + BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, JsonText); + BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, JsonText); + } + public string SerializeJsonNet(object value) { Type type = value.GetType(); @@ -237,44 +272,6 @@ namespace Newtonsoft.Json.Tests Console.WriteLine(value); Console.WriteLine(); } - - [Test] - public void Serialize() - { - TestClass test = new TestClass(); - - test.Address1.Address = "fff Street"; - test.Address1.Entered = DateTime.Now.AddDays(20); - - test.BigNumber = 34123123123.121M; - test.Now = DateTime.Now.AddHours(1); - test.strings = new List() { "Rick", "Markus egger ][, (2nd)", "Kevin McNeish" }; - - cAddress address = new cAddress(); - address.Entered = DateTime.Now.AddDays(-1); - address.Address = "array address"; - - test.Addresses.Add(address); - - address = new cAddress(); - address.Entered = DateTime.Now.AddDays(-2); - address.Address = "array 2 address"; - test.Addresses.Add(address); - - BenchmarkSerializeMethod(SerializeMethod.JsonNet, test); - BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, test); - BenchmarkSerializeMethod(SerializeMethod.JavaScriptSerializer, test); - BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, test); - } - - [Test] - public void Deserialize() - { - BenchmarkDeserializeMethod(SerializeMethod.JsonNet, JsonText); - BenchmarkDeserializeMethod(SerializeMethod.JsonNetBinary, MiscellaneousUtils.HexToBytes(BsonHex)); - BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, JsonText); - BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, JsonText); - } } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index c79140d9..8e03b585 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -855,7 +855,7 @@ keyword such as type of business."" PersonRaw personRaw = new PersonRaw { FirstName = "FirstNameValue", - RawContent = new JsonRaw("[1,2,3,4,5]"), + RawContent = new JRaw("[1,2,3,4,5]"), LastName = "LastNameValue" }; @@ -873,7 +873,7 @@ keyword such as type of business."" PersonRaw personRaw = JsonConvert.DeserializeObject(json); Assert.AreEqual("FirstNameValue", personRaw.FirstName); - Assert.AreEqual("[1,2,3,4,5]", personRaw.RawContent.Content); + Assert.AreEqual("[1,2,3,4,5]", personRaw.RawContent.ToString()); Assert.AreEqual("LastNameValue", personRaw.LastName); } @@ -1852,18 +1852,6 @@ keyword such as type of business."" Assert.AreEqual(@"[""str_1"",""str_2"",""str_3""]", json); } - public class ConstructorReadonlyFields - { - public readonly string A; - public readonly int B; - - public ConstructorReadonlyFields(string a, int b) - { - A = a; - B = b; - } - } - [Test] public void ConstructorReadonlyFieldsTest() { @@ -1879,14 +1867,6 @@ keyword such as type of business."" Assert.AreEqual(int.MaxValue, c2.B); } - public struct StructTest - { - public string StringProperty { get; set; } - public string StringField; - public int IntProperty { get; set; } - public int IntField; - } - [Test] public void SerializeStruct() { @@ -1914,62 +1894,6 @@ keyword such as type of business."" Assert.AreEqual(structTest.IntField, deserialized.IntField); } - public class ListOfIds : JsonConverter where T : Bar, new() - { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - IList list = (IList) value; - - writer.WriteStartArray(); - foreach (T item in list) - { - writer.WriteValue(item.Id); - } - writer.WriteEndArray(); - } - - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) - { - IList list = new List(); - - reader.Read(); - while (reader.TokenType != JsonToken.EndArray) - { - long id = (long)reader.Value; - - list.Add(new T - { - Id = Convert.ToInt32(id) - }); - - reader.Read(); - } - - return list; - } - - public override bool CanConvert(Type objectType) - { - return typeof (IList).IsAssignableFrom(objectType); - } - } - - public class Foo - { - public Foo() - { - Bars = new List(); - } - - [JsonConverter(typeof(ListOfIds))] - public List Bars { get; set; } - } - - public class Bar - { - public int Id { get; set; } - } - [Test] public void SerializeListWithJsonConverter() { @@ -2019,13 +1943,6 @@ keyword such as type of business."" JsonConvert.SerializeObject(dictionary, Formatting.Indented); } - public class SearchResult - { - public string Title { get; set; } - public string Content { get; set; } - public string Url { get; set; } - } - [Test] public void SerializeFragment() { @@ -2106,5 +2023,33 @@ keyword such as type of business."" Assert.AreEqual("Paris Hilton - Wikipedia, the free encyclopedia", searchResults[0].Title); Assert.AreEqual("Paris Hilton", searchResults[1].Title); } + + [Test] + public void DeserializeBaseReferenceWithDerivedValue() + { + PersonPropertyClass personPropertyClass = new PersonPropertyClass(); + WagePerson wagePerson = (WagePerson) personPropertyClass.Person; + + wagePerson.BirthDate = new DateTime(2000, 11, 29, 23, 59, 59, DateTimeKind.Utc); + wagePerson.Department = "McDees"; + wagePerson.HourlyWage = 12.50m; + wagePerson.LastModified = new DateTime(2000, 11, 29, 23, 59, 59, DateTimeKind.Utc); + wagePerson.Name = "Jim Bob"; + + string json = JsonConvert.SerializeObject(personPropertyClass, Formatting.Indented); + Assert.AreEqual( + @"{ + ""Person"": { + ""HourlyWage"": 12.50, + ""Name"": ""Jim Bob"", + ""BirthDate"": ""\/Date(975542399000)\/"", + ""LastModified"": ""\/Date(975542399000)\/"" + } +}", + json); + + PersonPropertyClass newPersonPropertyClass = JsonConvert.DeserializeObject(json); + Assert.AreEqual(wagePerson.HourlyWage, ((WagePerson) newPersonPropertyClass.Person).HourlyWage); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/PopulateTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/PopulateTests.cs index f3e65e9f..c63445de 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/PopulateTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/PopulateTests.cs @@ -30,6 +30,7 @@ using System.Linq; using System.Text; using Newtonsoft.Json.Tests.TestObjects; using NUnit.Framework; +using Newtonsoft.Json.Linq; namespace Newtonsoft.Json.Tests.Serialization { @@ -131,5 +132,12 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual(1, p.Count); Assert.AreEqual("James", p["Name"]); } + + [Test] + [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Unexpected initial token 'Integer' when populating object. Expected JSON object or array.")] + public void PopulateWithBadJson() + { + JsonConvert.PopulateObject("1", new Person()); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Bar.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Bar.cs new file mode 100644 index 00000000..a301951c --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Bar.cs @@ -0,0 +1,32 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Bar + { + public int Id { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Computer.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Computer.cs index f056c230..afb778cf 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/Computer.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Computer.cs @@ -1,9 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; using System.Runtime.Serialization; +#if !PocketPC && !NET20 namespace Newtonsoft.Json.Tests.TestObjects { [DataContract] @@ -22,3 +45,4 @@ namespace Newtonsoft.Json.Tests.TestObjects public DateTime NextShipmentDate { get; set; } } } +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConstructorReadonlyFields.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConstructorReadonlyFields.cs new file mode 100644 index 00000000..5fac9879 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConstructorReadonlyFields.cs @@ -0,0 +1,39 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ConstructorReadonlyFields + { + public readonly string A; + public readonly int B; + + public ConstructorReadonlyFields(string a, int b) + { + A = a; + B = b; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Foo.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Foo.cs new file mode 100644 index 00000000..40228928 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Foo.cs @@ -0,0 +1,40 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class Foo + { + public Foo() + { + Bars = new List(); + } + + [JsonConverter(typeof(ListOfIds))] + public List Bars { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs new file mode 100644 index 00000000..617f229c --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs @@ -0,0 +1,70 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class ListOfIds : JsonConverter where T : Bar, new() + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + IList list = (IList)value; + + writer.WriteStartArray(); + foreach (T item in list) + { + writer.WriteValue(item.Id); + } + writer.WriteEndArray(); + } + + public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + { + IList list = new List(); + + reader.Read(); + while (reader.TokenType != JsonToken.EndArray) + { + long id = (long)reader.Value; + + list.Add(new T + { + Id = Convert.ToInt32(id) + }); + + reader.Read(); + } + + return list; + } + + public override bool CanConvert(Type objectType) + { + return typeof(IList).IsAssignableFrom(objectType); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PersonPropertyClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PersonPropertyClass.cs new file mode 100644 index 00000000..a8d9a859 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PersonPropertyClass.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class PersonPropertyClass + { + public Person Person { get; set; } + + public PersonPropertyClass() + { + Person = new WagePerson(); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs index 2797fff2..79f50f60 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PersonRaw.cs @@ -24,6 +24,7 @@ #endregion using System; +using Newtonsoft.Json.Linq; namespace Newtonsoft.Json.Tests.TestObjects { @@ -32,7 +33,7 @@ namespace Newtonsoft.Json.Tests.TestObjects private Guid _internalId; private string _firstName; private string _lastName; - private JsonRaw _rawContent; + private JRaw _rawContent; [JsonIgnore] public Guid InternalId @@ -48,7 +49,7 @@ namespace Newtonsoft.Json.Tests.TestObjects set { _firstName = value; } } - public JsonRaw RawContent + public JRaw RawContent { get { return _rawContent; } set { _rawContent = value; } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/SearchResult.cs b/Src/Newtonsoft.Json.Tests/TestObjects/SearchResult.cs new file mode 100644 index 00000000..7a690348 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/SearchResult.cs @@ -0,0 +1,34 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class SearchResult + { + public string Title { get; set; } + public string Content { get; set; } + public string Url { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/StructTest.cs b/Src/Newtonsoft.Json.Tests/TestObjects/StructTest.cs new file mode 100644 index 00000000..e88529a3 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/StructTest.cs @@ -0,0 +1,35 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public struct StructTest + { + public string StringProperty { get; set; } + public string StringField; + public int IntProperty { get; set; } + public int IntField; + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/WagePerson.cs b/Src/Newtonsoft.Json.Tests/TestObjects/WagePerson.cs new file mode 100644 index 00000000..d8c267e3 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/WagePerson.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + public class WagePerson : Person + { + [JsonProperty] + public decimal HourlyWage { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index db5d1c7b..0041749d 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -399,6 +399,44 @@ namespace Newtonsoft.Json throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); } + private static bool IsJsonPrimitiveTypeCode(TypeCode typeCode) + { + switch (typeCode) + { + case TypeCode.String: + case TypeCode.Char: + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.Byte: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.DateTime: + case TypeCode.Decimal: + case TypeCode.DBNull: + return true; + default: + return false; + } + } + + internal static bool IsJsonPrimitiveType(Type type) + { +#if !PocketPC && !NET20 + if (type == typeof(DateTimeOffset)) + return true; +#endif + if (type == typeof(byte[])) + return true; + + return IsJsonPrimitiveTypeCode(Type.GetTypeCode(type)); + } + internal static bool IsJsonPrimitive(object value) { if (value == null) @@ -408,28 +446,7 @@ namespace Newtonsoft.Json { IConvertible convertible = (IConvertible)value; - switch (convertible.GetTypeCode()) - { - case TypeCode.String: - case TypeCode.Char: - case TypeCode.Boolean: - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.Byte: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.DateTime: - case TypeCode.Decimal: - case TypeCode.DBNull: - return true; - default: - return false; - } + return IsJsonPrimitiveTypeCode(convertible.GetTypeCode()); } #if !PocketPC && !NET20 diff --git a/Src/Newtonsoft.Json/JsonRaw.cs b/Src/Newtonsoft.Json/JsonRaw.cs deleted file mode 100644 index ce9152c4..00000000 --- a/Src/Newtonsoft.Json/JsonRaw.cs +++ /dev/null @@ -1,121 +0,0 @@ -#region License -// Copyright (c) 2007 James Newton-King -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -#endregion - -using System; -using System.Collections; -using System.Globalization; -using System.IO; -using System.Text; -using System.Text.RegularExpressions; -using System.Collections.Generic; -using System.ComponentModel; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Utilities; - -namespace Newtonsoft.Json -{ - /// - /// Raw JSON content. - /// - public class JsonRaw - { - private string _content; - - /// - /// Gets the raw JSON string. - /// - /// The raw JSON string. - public string Content - { - get { return _content; } - } - - /// - /// Initializes a new instance of the class. - /// - /// The content. - public JsonRaw(string content) - { - ValidationUtils.ArgumentNotNull(content, "content"); - - _content = content; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// - /// true if the specified is equal to the current ; otherwise, false. - /// - /// The parameter is null. - public override bool Equals(object obj) - { - JsonRaw raw = obj as JsonRaw; - if (raw == null) - return false; - - return (string.Compare(_content, raw.Content, StringComparison.OrdinalIgnoreCase) == 0); - } - - /// - /// Serves as a hash function for a particular type. - /// - /// - /// A hash code for the current . - /// - public override int GetHashCode() - { - return _content.GetHashCode(); - } - - /// - /// Returns a that represents the current . - /// - /// - /// A that represents the current . - /// - public override string ToString() - { - return _content; - } - - /// - /// Creates an instance of with the content of the reader's current token. - /// - /// The reader. - /// An instance of with the content of the reader's current token. - public static JsonRaw Create(JsonReader reader) - { - using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) - using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) - { - jsonWriter.WriteToken(reader); - - return new JsonRaw(sw.ToString()); - } - } - } -} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index 0403b057..9f5ba7c0 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -418,12 +418,11 @@ namespace Newtonsoft.Json serializerWriter.Serialize(jsonWriter, value); } - internal bool HasClassConverter(Type objectType, out JsonConverter converter) + internal bool HasClassConverter(JsonContract contract, out JsonConverter converter) { - if (objectType == null) - throw new ArgumentNullException("objectType"); + if (contract == null) + throw new ArgumentNullException("contract"); - JsonContract contract = ContractResolver.ResolveContract(objectType); converter = contract.Converter; return (converter != null); diff --git a/Src/Newtonsoft.Json/Linq/JRaw.cs b/Src/Newtonsoft.Json/Linq/JRaw.cs new file mode 100644 index 00000000..a6db8f61 --- /dev/null +++ b/Src/Newtonsoft.Json/Linq/JRaw.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Linq +{ + /// + /// Represents a raw JSON string. + /// + public class JRaw : JValue + { + /// + /// Initializes a new instance of the class from another object. + /// + /// A object to copy from. + public JRaw(JRaw other) + : base(other) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The raw json. + public JRaw(string rawJson) + : base(rawJson, JTokenType.Raw) + { + } + + /// + /// Creates an instance of with the content of the reader's current token. + /// + /// The reader. + /// An instance of with the content of the reader's current token. + public static JRaw Create(JsonReader reader) + { + using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.WriteToken(reader); + + return new JRaw(sw.ToString()); + } + } + + internal override JToken CloneToken() + { + return new JRaw(this); + } + + //public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) + //{ + // writer.WriteRawValue(Value); + //} + + //internal override JToken CloneToken() + //{ + // throw new NotImplementedException(); + //} + + //internal override bool DeepEquals(JToken node) + //{ + // JRaw other = node as JRaw; + // if (other == null) + // return false; + + // return (this == other || string.Equals(Value, other.Value, StringComparison.Ordinal)); + //} + + //public override JTokenType Type + //{ + // get { return JTokenType.Raw; } + //} + + //public override bool HasValues + //{ + // get { return false; } + //} + + //internal override int GetDeepHashCode() + //{ + // return Value.GetHashCode(); + //} + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs index e5cee0cf..ddb68b9a 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs @@ -180,7 +180,7 @@ namespace Newtonsoft.Json.Linq public override void WriteRaw(string json) { base.WriteRaw(json); - AddValue(JValue.CreateRaw(json), JsonToken.Raw); + AddValue(new JRaw(json), JsonToken.Raw); } /// diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 57255110..3d954604 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -124,7 +124,7 @@ namespace Newtonsoft.Json.Linq if (other == null) return false; - return (this == other || (_valueType == other.Type && Compare(_value, other.Value))); + return ValuesEquals(this, other); } /// @@ -138,14 +138,14 @@ namespace Newtonsoft.Json.Linq get { return false; } } - private bool Compare(object objA, object objB) + private static bool Compare(JTokenType valueType, object objA, object objB) { if (objA == null && objB == null) return true; if (objA == null || objB == null) return false; - switch (_valueType) + switch (valueType) { case JTokenType.Integer: if (objA is ulong || objB is ulong) @@ -157,6 +157,7 @@ namespace Newtonsoft.Json.Linq case JTokenType.Comment: case JTokenType.String: case JTokenType.Boolean: + case JTokenType.Raw: return objA.Equals(objB); case JTokenType.Date: return objA.Equals(objB); @@ -168,7 +169,7 @@ namespace Newtonsoft.Json.Linq return MiscellaneousUtils.ByteArrayCompare(b1, b2); default: - throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", _valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, _valueType)); + throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, valueType)); } } @@ -197,17 +198,6 @@ namespace Newtonsoft.Json.Linq return new JValue(value, JTokenType.String); } - - /// - /// Creates a of raw JSON with the given value. - /// - /// The value. - /// A of raw JSON with the given value. - public static JValue CreateRaw(string value) - { - return new JValue(value, JTokenType.Raw); - } - private static JTokenType GetValueType(JTokenType? current, object value) { if (value == null) @@ -324,12 +314,12 @@ namespace Newtonsoft.Json.Linq writer.WriteValue(Convert.ToDateTime(v, CultureInfo.InvariantCulture)); }, _value); break; + case JTokenType.Raw: + writer.WriteRawValue((string)_value); + break; case JTokenType.Bytes: WriteConvertableValue(writer, converters, v => writer.WriteValue((byte[])v), _value); break; - case JTokenType.Raw: - writer.WriteRawValue(_value.ToString()); - break; case JTokenType.Null: writer.WriteNull(); break; @@ -348,6 +338,11 @@ namespace Newtonsoft.Json.Linq return _valueType.GetHashCode() ^ valueHashCode; } + private static bool ValuesEquals(JValue v1, JValue v2) + { + return (v1 == v2|| (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value))); + } + /// /// Indicates whether the current object is equal to another object of the same type. /// @@ -360,7 +355,7 @@ namespace Newtonsoft.Json.Linq if (other == null) return false; - return (_value == other._value); + return ValuesEquals(this, other); } /// diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj index 75491644..48f03403 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj @@ -78,6 +78,7 @@ + @@ -95,7 +96,6 @@ - @@ -147,7 +147,9 @@ + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index d976e8e7..18c6920b 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -89,6 +89,7 @@ + @@ -115,7 +116,6 @@ - @@ -156,6 +156,8 @@ + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index 0b8e841c..274c90fb 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -78,7 +78,6 @@ - @@ -102,6 +101,7 @@ + @@ -131,7 +131,9 @@ + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index faf940f7..9ab83edf 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -90,7 +90,10 @@ + + + @@ -121,7 +124,6 @@ - diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index ec5f0aaf..9868d3b1 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -33,6 +33,7 @@ using System.Reflection; using System.Runtime.Serialization; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Utilities; +using Newtonsoft.Json.Linq; namespace Newtonsoft.Json.Serialization { @@ -79,6 +80,9 @@ namespace Newtonsoft.Json.Serialization /// The contract for a given type. public virtual JsonContract ResolveContract(Type type) { + if (type == null) + throw new ArgumentNullException("type"); + return _typeContractCache.Get(type); } @@ -283,8 +287,38 @@ namespace Newtonsoft.Json.Serialization return contract; } + /// + /// Creates a for the given type. + /// + /// Type of the object. + /// A for the given type. + protected virtual JsonPrimitiveContract CreatePrimitiveContract(Type objectType) + { + JsonPrimitiveContract contract = new JsonPrimitiveContract(objectType); + InitializeContract(contract); + + return contract; + } + + /// + /// Creates a for the given type. + /// + /// Type of the object. + /// A for the given type. + protected virtual JsonLinqContract CreateLinqContract(Type objectType) + { + JsonLinqContract contract = new JsonLinqContract(objectType); + InitializeContract(contract); + + return contract; + } + private JsonContract CreateContract(Type objectType) { + if (JsonConvert.IsJsonPrimitiveType(objectType)) + { + return CreatePrimitiveContract(objectType); + } if (JsonTypeReflector.GetJsonObjectAttribute(objectType) != null) { return CreateObjectContract(objectType); @@ -297,6 +331,10 @@ namespace Newtonsoft.Json.Serialization { return CreateArrayContract(objectType); } + if (objectType.IsSubclassOf(typeof(JToken))) + { + return CreateLinqContract(objectType); + } return CreateObjectContract(objectType); } diff --git a/Src/Newtonsoft.Json/Serialization/JsonLinqContract.cs b/Src/Newtonsoft.Json/Serialization/JsonLinqContract.cs new file mode 100644 index 00000000..795ff9f0 --- /dev/null +++ b/Src/Newtonsoft.Json/Serialization/JsonLinqContract.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Serialization +{ + /// + /// Contract details for a used by the . + /// + public class JsonLinqContract : JsonContract + { + /// + /// Initializes a new instance of the class. + /// + /// The underlying type for the contract. + public JsonLinqContract(Type underlyingType) + : base(underlyingType) + { + CreatedType = underlyingType; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs b/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs new file mode 100644 index 00000000..a0e04bc3 --- /dev/null +++ b/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs @@ -0,0 +1,45 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Serialization +{ + /// + /// Contract details for a used by the . + /// + public class JsonPrimitiveContract : JsonContract + { + /// + /// Initializes a new instance of the class. + /// + /// The underlying type for the contract. + public JsonPrimitiveContract(Type underlyingType) + : base(underlyingType) + { + CreatedType = underlyingType; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index cf7eddc3..4c38583d 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -81,6 +81,26 @@ namespace Newtonsoft.Json.Serialization else throw new JsonSerializationException("Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType)); } + else + { + throw new JsonSerializationException("Unexpected initial token '{0}' when populating object. Expected JSON object or array.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); + } + } + + private JsonContract GetContractSafe(Type type) + { + if (type == null) + return null; + + return Serializer.ContractResolver.ResolveContract(type); + } + + private JsonContract GetContractSafe(Type type, object value) + { + if (value == null) + return GetContractSafe(type); + + return Serializer.ContractResolver.ResolveContract(value.GetType()); } public object Deserialize(JsonReader reader, Type objectType) @@ -91,7 +111,7 @@ namespace Newtonsoft.Json.Serialization if (reader.TokenType == JsonToken.None && !reader.Read()) return null; - return CreateValue(reader, objectType, null, null); + return CreateValue(reader, objectType, GetContractSafe(objectType), null, null); } private JsonSerializerProxy GetInternalSerializer() @@ -102,26 +122,32 @@ namespace Newtonsoft.Json.Serialization return _internalSerializer; } - private JToken CreateJToken(JsonReader reader) + private JToken CreateJToken(JsonReader reader, JsonContract contract) { ValidationUtils.ArgumentNotNull(reader, "reader"); - JToken token; - using (JTokenWriter writer = new JTokenWriter()) + if (contract != null && contract.UnderlyingType == typeof(JRaw)) { - writer.WriteToken(reader); - token = writer.Token; + return JRaw.Create(reader); } + else + { + JToken token; + using (JTokenWriter writer = new JTokenWriter()) + { + writer.WriteToken(reader); + token = writer.Token; + } - return token; + return token; + } } private JToken CreateJObject(JsonReader reader) { ValidationUtils.ArgumentNotNull(reader, "reader"); -// throw new Exception("Expected current token of type {0}, got {1}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.PropertyName, reader.TokenType)); - + // this is needed because we've already read inside the object, looking for special properties JToken token; using (JTokenWriter writer = new JTokenWriter()) { @@ -138,21 +164,21 @@ namespace Newtonsoft.Json.Serialization return token; } - private object CreateValue(JsonReader reader, Type objectType, object existingValue, JsonConverter memberConverter) + private object CreateValue(JsonReader reader, Type objectType, JsonContract contract, object existingValue, JsonConverter memberConverter) { JsonConverter converter; if (memberConverter != null) return memberConverter.ReadJson(reader, objectType, GetInternalSerializer()); - if (objectType != null && Serializer.HasClassConverter(objectType, out converter)) + if (objectType != null && Serializer.HasClassConverter(contract, out converter)) return converter.ReadJson(reader, objectType, GetInternalSerializer()); if (objectType != null && Serializer.HasMatchingConverter(objectType, out converter)) return converter.ReadJson(reader, objectType, GetInternalSerializer()); - if (objectType == typeof (JsonRaw)) - return JsonRaw.Create(reader); + if (contract is JsonLinqContract) + return CreateJToken(reader, contract); do { @@ -161,9 +187,9 @@ namespace Newtonsoft.Json.Serialization // populate a typed object or generic dictionary/array // depending upon whether an objectType was supplied case JsonToken.StartObject: - return CreateObject(reader, objectType, existingValue); + return CreateObject(reader, objectType, contract, existingValue); case JsonToken.StartArray: - return CreateList(reader, objectType, existingValue, null); + return CreateList(reader, objectType, contract, existingValue, null); case JsonToken.Integer: case JsonToken.Float: case JsonToken.Boolean: @@ -189,6 +215,8 @@ namespace Newtonsoft.Json.Serialization return DBNull.Value; return EnsureType(reader.Value, objectType); + case JsonToken.Raw: + return new JRaw((string)reader.Value); case JsonToken.Comment: // ignore break; @@ -200,7 +228,7 @@ namespace Newtonsoft.Json.Serialization throw new JsonSerializationException("Unexpected end when deserializing object."); } - private object CreateObject(JsonReader reader, Type objectType, object existingValue) + private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, object existingValue) { CheckedRead(reader); @@ -252,6 +280,7 @@ namespace Newtonsoft.Json.Serialization 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; } @@ -266,7 +295,7 @@ namespace Newtonsoft.Json.Serialization else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) { CheckedRead(reader); - object list = CreateList(reader, objectType, existingValue, id); + object list = CreateList(reader, objectType, contract, existingValue, id); CheckedRead(reader); return list; } @@ -281,8 +310,6 @@ namespace Newtonsoft.Json.Serialization if (!HasDefinedType(objectType)) return CreateJObject(reader); - JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType); - if (contract == null) throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType)); @@ -305,9 +332,8 @@ namespace Newtonsoft.Json.Serialization throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType)); } - private JsonArrayContract GetArrayContract(Type objectType) + private JsonArrayContract EnsureArrayContract(Type objectType, JsonContract contract) { - JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType); if (contract == null) throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType)); @@ -324,28 +350,28 @@ namespace Newtonsoft.Json.Serialization throw new JsonSerializationException("Unexpected end when deserializing object."); } - private object CreateList(JsonReader reader, Type objectType, object existingValue, string reference) + private object CreateList(JsonReader reader, Type objectType, JsonContract contract, object existingValue, string reference) { object value; if (HasDefinedType(objectType)) { - JsonArrayContract contract = GetArrayContract(objectType); + JsonArrayContract arrayContract = EnsureArrayContract(objectType, contract); if (existingValue == null) - value = CreateAndPopulateList(reader, reference, contract); + value = CreateAndPopulateList(reader, reference, arrayContract); else - value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), reader, reference, contract); + value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), reader, reference, arrayContract); } else { - value = CreateJToken(reader); + value = CreateJToken(reader, contract); } return value; } private bool HasDefinedType(Type type) { - return (type != null && type != typeof (object)); + return (type != null && type != typeof (object) && !type.IsSubclassOf(typeof(JToken))); } private object EnsureType(object value, Type targetType) @@ -412,7 +438,8 @@ namespace Newtonsoft.Json.Serialization return; } - object value = CreateValue(reader, property.PropertyType, (useExistingValue) ? currentValue : null, property.Converter); + object existingValue = (useExistingValue) ? currentValue : null; + object value = CreateValue(reader, property.PropertyType, GetContractSafe(property.PropertyType, existingValue), existingValue, property.Converter); // always set the value if useExistingValue is false, // otherwise also set it if CreateValue returns a new value compared to the currentValue @@ -464,7 +491,7 @@ namespace Newtonsoft.Json.Serialization try { - dictionary.Add(keyValue, CreateValue(reader, contract.DictionaryValueType, null, null)); + dictionary.Add(keyValue, CreateValue(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType), null, null)); } catch (Exception ex) { @@ -528,7 +555,7 @@ namespace Newtonsoft.Json.Serialization default: try { - object value = CreateValue(reader, contract.CollectionItemType, null, null); + object value = CreateValue(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType), null, null); wrappedList.Add(value); } @@ -595,7 +622,7 @@ namespace Newtonsoft.Json.Serialization { if (!property.Ignored) { - propertyValues[property] = CreateValue(reader, property.PropertyType, null, property.MemberConverter); + propertyValues[property] = CreateValue(reader, property.PropertyType, GetContractSafe(property.PropertyType), null, property.MemberConverter); } } else diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index 825cfd87..6ed820aa 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -61,7 +61,7 @@ namespace Newtonsoft.Json.Serialization if (jsonWriter == null) throw new ArgumentNullException("jsonWriter"); - SerializeValue(jsonWriter, value, null); + SerializeValue(jsonWriter, value, null, GetContractSafe(value)); } private JsonSerializerProxy GetInternalSerializer() @@ -72,67 +72,70 @@ namespace Newtonsoft.Json.Serialization return _internalSerializer; } - private void SerializeValue(JsonWriter writer, object value, JsonConverter memberConverter) + private JsonContract GetContractSafe(object value) + { + if (value == null) + return null; + + return Serializer.ContractResolver.ResolveContract(value.GetType()); + } + + private void SerializeValue(JsonWriter writer, object value, JsonConverter memberConverter, JsonContract contract) { JsonConverter converter = memberConverter; if (value == null) { writer.WriteNull(); + return; } - else if (converter != null - || Serializer.HasClassConverter(value.GetType(), out converter) - || Serializer.HasMatchingConverter(value.GetType(), out converter)) + + if (converter != null + || Serializer.HasClassConverter(contract, out converter) + || Serializer.HasMatchingConverter(contract.UnderlyingType, out converter)) { - SerializeConvertable(writer, converter, value); + SerializeConvertable(writer, converter, value, contract); } - else if (JsonConvert.IsJsonPrimitive(value)) + else if (contract is JsonPrimitiveContract) { writer.WriteValue(value); } else if (value is JToken) { - ((JToken)value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null); + ((JToken) value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null); } - else if (value is JsonRaw) + else if (contract is JsonObjectContract) { - writer.WriteRawValue(((JsonRaw)value).Content); + SerializeObject(writer, value, (JsonObjectContract) contract); } - else + else if (contract is JsonDictionaryContract) { - JsonContract contract = Serializer.ContractResolver.ResolveContract(value.GetType()); - - if (contract is JsonObjectContract) + SerializeDictionary(writer, (IDictionary) value, (JsonDictionaryContract) contract); + } + else if (contract is JsonArrayContract) + { + if (value is IList) { - SerializeObject(writer, value, (JsonObjectContract)contract); + SerializeList(writer, (IList) value, (JsonArrayContract) contract); } - else if (contract is JsonDictionaryContract) + else if (value is IEnumerable) { - SerializeDictionary(writer, (IDictionary)value, (JsonDictionaryContract)contract); + SerializeEnumerable(writer, (IEnumerable) value, (JsonArrayContract) contract); } - else if (contract is JsonArrayContract) + else { - if (value is IList) - { - SerializeList(writer, (IList)value, (JsonArrayContract)contract); - } - else if (value is IEnumerable) - { - SerializeEnumerable(writer, (IEnumerable)value, (JsonArrayContract)contract); - } - else - { - throw new Exception("Cannot serialize '{0}' into a JSON array. Type does not implement IEnumerable.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); - } + throw new Exception( + "Cannot serialize '{0}' into a JSON array. Type does not implement IEnumerable.".FormatWith( + CultureInfo.InvariantCulture, value.GetType())); } } } - private bool ShouldWriteReference(object value, JsonProperty property) + private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract) { if (value == null) return false; - if (JsonConvert.IsJsonPrimitive(value)) + if (contract is JsonPrimitiveContract) return false; bool? isReference = null; @@ -142,11 +145,7 @@ namespace Newtonsoft.Json.Serialization isReference = property.IsReference; if (isReference == null) - { - JsonContract memberTypeContract = Serializer.ContractResolver.ResolveContract(value.GetType()); - if (memberTypeContract != null) - isReference = memberTypeContract.IsReference; - } + isReference = contract.IsReference; if (isReference == null) { @@ -166,14 +165,12 @@ namespace Newtonsoft.Json.Serialization return Serializer.ReferenceResolver.IsReferenced(value); } - private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonProperty property) + private void WriteMemberInfoProperty(JsonWriter writer, object value, object memberValue, JsonProperty property, JsonContract contract) { string propertyName = property.PropertyName; JsonConverter memberConverter = property.MemberConverter; object defaultValue = property.DefaultValue; - object memberValue = property.ValueProvider.GetValue(value); - if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && memberValue == null) return; @@ -182,7 +179,7 @@ namespace Newtonsoft.Json.Serialization DefaultValueHandling.Ignore && Equals(memberValue, defaultValue)) return; - if (ShouldWriteReference(memberValue, property)) + if (ShouldWriteReference(memberValue, property, contract)) { writer.WritePropertyName(propertyName); WriteReference(writer, memberValue); @@ -193,7 +190,7 @@ namespace Newtonsoft.Json.Serialization return; writer.WritePropertyName(propertyName); - SerializeValue(writer, memberValue, memberConverter); + SerializeValue(writer, memberValue, memberConverter, contract); } private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling) @@ -294,7 +291,12 @@ namespace Newtonsoft.Json.Serialization try { if (!property.Ignored && property.Readable) - WriteMemberInfoProperty(writer, value, property); + { + object memberValue = property.ValueProvider.GetValue(value); + JsonContract memberContract = GetContractSafe(memberValue); + + WriteMemberInfoProperty(writer, value, memberValue, property, memberContract); + } } catch (Exception ex) { @@ -327,9 +329,9 @@ namespace Newtonsoft.Json.Serialization return ((value & flag) == flag); } - private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value) + private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract) { - if (ShouldWriteReference(value, null)) + if (ShouldWriteReference(value, null, contract)) { WriteReference(writer, value); } @@ -385,8 +387,9 @@ namespace Newtonsoft.Json.Serialization try { object value = values[i]; + JsonContract valueContract = GetContractSafe(value); - if (ShouldWriteReference(value, null)) + if (ShouldWriteReference(value, null, valueContract)) { WriteReference(writer, value); } @@ -395,7 +398,7 @@ namespace Newtonsoft.Json.Serialization if (!CheckForCircularReference(value, null)) continue; - SerializeValue(writer, value, null); + SerializeValue(writer, value, null, valueContract); } } catch (Exception ex) @@ -446,8 +449,9 @@ namespace Newtonsoft.Json.Serialization try { object value = entry.Value; + JsonContract valueContract = GetContractSafe(value); - if (ShouldWriteReference(value, null)) + if (ShouldWriteReference(value, null, valueContract)) { writer.WritePropertyName(propertyName); WriteReference(writer, value); @@ -459,7 +463,7 @@ namespace Newtonsoft.Json.Serialization writer.WritePropertyName(propertyName); - SerializeValue(writer, value, null); + SerializeValue(writer, value, null, valueContract); } } catch (Exception ex)