diff options
25 files changed, 863 insertions, 197 deletions
diff --git a/Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs b/Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs deleted file mode 100644 index f76ded5..0000000 --- a/Src/Newtonsoft.Json.Tests/AspNetAjaxDateTimeConverterTest.cs +++ /dev/null @@ -1,70 +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.Generic;
-using System.Text;
-using NUnit.Framework;
-using Newtonsoft.Json;
-using System.IO;
-using Newtonsoft.Json.Converters;
-
-namespace Newtonsoft.Json.Tests
-{
- [TestFixture]
- public class AspNetAjaxDateTimeConverterTest
- {
- public class DateTimeTestClass
- {
- public string PreField;
- public DateTime DateTimeField;
- public string PostField;
- }
-
- [Test]
- public void Serialize()
- {
- DateTimeTestClass c = new DateTimeTestClass();
- c.DateTimeField = new DateTime(2008, 12, 12, 12, 12, 12, 12);
- c.PreField = "Pre";
- c.PostField = "Post";
-
- string json = JavaScriptConvert.SerializeObject(c, new AspNetAjaxDateTimeConverter());
-
- Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":""@1229083932012@"",""PostField"":""Post""}", json);
- }
-
- [Test]
- public void DeSerialize()
- {
- DateTimeTestClass c =
- JavaScriptConvert.DeserializeObject<DateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":""@1229083932012@"",""PostField"":""Post""}", new AspNetAjaxDateTimeConverter());
-
- Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 12), c.DateTimeField);
- Assert.AreEqual("Pre", c.PreField);
- Assert.AreEqual("Post", c.PostField);
- }
- }
-}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs b/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs new file mode 100644 index 0000000..558a740 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/DateTimeTestClass.cs @@ -0,0 +1,14 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Tests
+{
+ public class DateTimeTestClass
+ {
+ public string PreField { get; set; }
+ public DateTime DateTimeField { get; set; }
+ public string PostField { get; set; }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/IsoDateTimeConverterTests.cs new file mode 100644 index 0000000..8b3580d --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/IsoDateTimeConverterTests.cs @@ -0,0 +1,95 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Utilities;
+using System.Globalization;
+
+namespace Newtonsoft.Json.Tests
+{
+ public class IsoDateTimeConverterTests : TestFixtureBase
+ {
+ [Test]
+ public void SerializeDateTime()
+ {
+ IsoDateTimeConverter converter = new IsoDateTimeConverter();
+
+ DateTime d = new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc);
+ string result;
+
+ result = JavaScriptConvert.SerializeObject(d, converter);
+ Assert.AreEqual(@"""2000-12-15T22:11:03.0550000Z""", result);
+
+ Assert.AreEqual(d, JavaScriptConvert.DeserializeObject<DateTime>(result, converter));
+
+ d = new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Local);
+ result = JavaScriptConvert.SerializeObject(d, converter);
+ Assert.AreEqual(@"""2000-12-15T22:11:03.0550000" + d.GetLocalOffset() + @"""", result);
+ }
+
+ [Test]
+ public void SerializeDateTimeOffset()
+ {
+ IsoDateTimeConverter converter = new IsoDateTimeConverter();
+
+ DateTimeOffset d = new DateTimeOffset(2000, 12, 15, 22, 11, 3, 55, TimeSpan.Zero);
+ string result;
+
+ result = JavaScriptConvert.SerializeObject(d, converter);
+ Assert.AreEqual(@"""2000-12-15T22:11:03.0550000+00:00""", result);
+
+ Assert.AreEqual(d, JavaScriptConvert.DeserializeObject<DateTimeOffset>(result, converter));
+ }
+
+ [Test]
+ public void SerializeUTC()
+ {
+ DateTimeTestClass c = new DateTimeTestClass();
+ c.DateTimeField = new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime();
+ c.PreField = "Pre";
+ c.PostField = "Post";
+ string json = JavaScriptConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
+ Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12.0000000Z"",""PostField"":""Post""}", json);
+
+ //test the other edge case too
+ c.DateTimeField = new DateTime(2008, 1, 1, 1, 1, 1, 0, DateTimeKind.Utc).ToLocalTime();
+ c.PreField = "Pre";
+ c.PostField = "Post";
+ json = JavaScriptConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
+ Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":""2008-01-01T01:01:01.0000000Z"",""PostField"":""Post""}", json);
+ }
+
+ [Test]
+ public void DeserializeUTC()
+ {
+ DateTimeTestClass c =
+ JavaScriptConvert.DeserializeObject<DateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12Z"",""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
+
+ Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(), c.DateTimeField);
+ Assert.AreEqual("Pre", c.PreField);
+ Assert.AreEqual("Post", c.PostField);
+
+ DateTimeTestClass c2 =
+ JavaScriptConvert.DeserializeObject<DateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":""2008-01-01T01:01:01Z"",""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
+
+ Assert.AreEqual(new DateTime(2008, 1, 1, 1, 1, 1, 0, DateTimeKind.Utc).ToLocalTime(), c2.DateTimeField);
+ Assert.AreEqual("Pre", c2.PreField);
+ Assert.AreEqual("Post", c2.PostField);
+ }
+
+ [Test]
+ public void SerializeShouldChangeNonUTCDates()
+ {
+ DateTimeTestClass c = new DateTimeTestClass();
+ c.DateTimeField = new DateTime(2008, 1, 1, 1, 1, 1, 0, DateTimeKind.Local);
+ c.PreField = "Pre";
+ c.PostField = "Post";
+ string json = JavaScriptConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); //note that this fails without the Utc converter...
+ c.DateTimeField = new DateTime(2008, 1, 1, 1, 1, 1, 0, DateTimeKind.Utc);
+ string json2 = JavaScriptConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
+ Assert.AreNotEqual(json, json2);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs b/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs index 63bf85b..917e23a 100644 --- a/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JavaScriptConvertTest.cs @@ -6,8 +6,7 @@ using NUnit.Framework; namespace Newtonsoft.Json.Tests
{
- [TestFixture]
- public class JavaScriptConvertTest
+ public class JavaScriptConvertTest : TestFixtureBase
{
[Test]
public void EscapeJavaScriptString()
diff --git a/Src/Newtonsoft.Json.Tests/JavaScriptDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/JavaScriptDateTimeConverterTests.cs new file mode 100644 index 0000000..cf7288b --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/JavaScriptDateTimeConverterTests.cs @@ -0,0 +1,57 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Newtonsoft.Json.Converters;
+
+namespace Newtonsoft.Json.Tests
+{
+ public class JavaScriptDateTimeConverterTests : TestFixtureBase
+ {
+ [Test]
+ public void SerializeDateTime()
+ {
+ JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter();
+
+ DateTime d = new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc);
+ string result;
+
+ result = JavaScriptConvert.SerializeObject(d, converter);
+ Assert.AreEqual("new Date(976918263055)", result);
+ }
+
+ [Test]
+ public void SerializeDateTimeOffset()
+ {
+ JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter();
+
+ DateTimeOffset now = new DateTimeOffset(2000, 12, 15, 22, 11, 3, 55, TimeSpan.Zero);
+ string result;
+
+ result = JavaScriptConvert.SerializeObject(now, converter);
+ Assert.AreEqual("new Date(976918263055)", result);
+ }
+
+ [Test]
+ public void DeserializeDateTime()
+ {
+ JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter();
+
+ DateTime result = JavaScriptConvert.DeserializeObject<DateTime>("new Date(976918263055)", converter);
+ Assert.AreEqual(new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc), result);
+ }
+
+ [Test]
+ public void DeserializeDateTimeOffset()
+ {
+ JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter();
+ DateTimeOffset start = new DateTimeOffset(2000, 12, 15, 22, 11, 3, 55, TimeSpan.Zero);
+
+ string json = JavaScriptConvert.SerializeObject(start, converter);
+
+ DateTimeOffset result = JavaScriptConvert.DeserializeObject<DateTimeOffset>(json, converter);
+ Assert.AreEqual(new DateTimeOffset(2000, 12, 15, 22, 11, 3, 55, TimeSpan.Zero), result);
+ }
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs index 5bb32aa..f94a88a 100644 --- a/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonReaderTest.cs @@ -32,8 +32,7 @@ using System.IO; namespace Newtonsoft.Json.Tests
{
- [TestFixture]
- public class JsonReaderTest
+ public class JsonReaderTest : TestFixtureBase
{
[Test]
public void YahooFinance()
diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index c136129..a8ef48b 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -35,20 +35,25 @@ using System.Xml.Serialization; using System.Collections.ObjectModel;
using System.Runtime.Serialization.Json;
using System.Net.Mail;
+using System.Web.Script.Serialization;
namespace Newtonsoft.Json.Tests
{
public class Product
{
public string Name;
- public DateTime Expiry;
+ public DateTime Expiry = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public decimal Price;
public string[] Sizes;
public override bool Equals(object obj)
{
if (obj is Product)
- return ((Product)obj).Name == Name;
+ {
+ Product p = (Product)obj;
+
+ return (p.Name == Name && p.Expiry == Expiry && p.Price == Price);
+ }
return base.Equals(obj);
}
@@ -74,7 +79,7 @@ namespace Newtonsoft.Json.Tests public class Store
{
public StoreColor Color = StoreColor.Yellow;
- public DateTime Establised = new DateTime(2010, 1, 22);
+ public DateTimeOffset Establised = new DateTimeOffset(2010, 1, 22, 1, 1, 1, TimeSpan.Zero);
public double Width = 1.1;
public int Employees = 999;
public int[] RoomsPerFloor = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
@@ -94,7 +99,7 @@ namespace Newtonsoft.Json.Tests Product rocket = new Product();
rocket.Name = "Rocket";
- rocket.Expiry = new DateTime(2000, 2, 2, 23, 1, 30);
+ rocket.Expiry = new DateTime(2000, 2, 2, 23, 1, 30, DateTimeKind.Utc);
Product alien = new Product();
alien.Name = "Alien";
@@ -111,8 +116,7 @@ namespace Newtonsoft.Json.Tests White
}
- [TestFixture]
- public class JsonSerializerTest
+ public class JsonSerializerTest : TestFixtureBase
{
[Test]
public void PersonTypedObjectDeserialization()
@@ -627,6 +631,46 @@ keyword such as type of business."" }
[Test]
+ public void DateTime()
+ {
+ List<DateTime> testDates = new List<DateTime> {
+ new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Local),
+ new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Unspecified),
+ new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Utc),
+ new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Local),
+ new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Unspecified),
+ new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc),
+ };
+ string result;
+
+
+ MemoryStream ms = new MemoryStream();
+ DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(List<DateTime>));
+ s.WriteObject(ms, testDates);
+ ms.Seek(0, SeekOrigin.Begin);
+ StreamReader sr = new StreamReader(ms);
+
+ string expected = sr.ReadToEnd();
+
+ result = JavaScriptConvert.SerializeObject(testDates);
+ Assert.AreEqual(expected, result);
+ }
+
+ [Test]
+ public void DateTimeOffset()
+ {
+ List<DateTimeOffset> testDates = new List<DateTimeOffset> {
+ new DateTimeOffset(new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Utc)),
+ new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.Zero),
+ new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(13)),
+ new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(-3.5)),
+ };
+
+ string result = JavaScriptConvert.SerializeObject(testDates);
+ Assert.AreEqual(@"[""\/Date(-59011455539000+0000)\/"",""\/Date(946688461000+0000)\/"",""\/Date(946641661000+1300)\/"",""\/Date(946701061000-0330)\/""]", result);
+ }
+
+ [Test]
public void NonStringKeyDictionary()
{
Dictionary<int, int> values = new Dictionary<int, int>();
@@ -645,10 +689,27 @@ keyword such as type of business."" [Test]
public void AnonymousObjectSerialization()
{
- var anonymous = new { StringValue = "I am a string", IntValue = int.MaxValue };
+ var anonymous =
+ new
+ {
+ StringValue = "I am a string",
+ IntValue = int.MaxValue,
+ NestedAnonymous = new { NestedValue = byte.MaxValue },
+ NestedArray = new[] { 1, 2 },
+ Product = new Product() { Name = "TestProduct" }
+ };
string json = JavaScriptConvert.SerializeObject(anonymous);
- Assert.AreEqual(@"{""StringValue"":""I am a string"",""IntValue"":2147483647}", json);
+ Assert.AreEqual(@"{""StringValue"":""I am a string"",""IntValue"":2147483647,""NestedAnonymous"":{""NestedValue"":255},""NestedArray"":[1,2],""Product"":{""Name"":""TestProduct"",""Expiry"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null}}", json);
+
+ anonymous = JavaScriptConvert.DeserializeAnonymousType(json, anonymous);
+ Assert.AreEqual("I am a string", anonymous.StringValue);
+ Assert.AreEqual(int.MaxValue, anonymous.IntValue);
+ Assert.AreEqual(255, anonymous.NestedAnonymous.NestedValue);
+ Assert.AreEqual(2, anonymous.NestedArray.Length);
+ Assert.AreEqual(1, anonymous.NestedArray[0]);
+ Assert.AreEqual(2, anonymous.NestedArray[1]);
+ Assert.AreEqual("TestProduct", anonymous.Product.Name);
}
[Test]
@@ -668,7 +729,7 @@ keyword such as type of business."" jsonSerializer.Serialize(sw, collection);
- Assert.AreEqual(@"[{""Name"":""Test1"",""Expiry"":new Date(-59011459200000),""Price"":0,""Sizes"":null},{""Name"":""Test2"",""Expiry"":new Date(-59011459200000),""Price"":0,""Sizes"":null},{""Name"":""Test3"",""Expiry"":new Date(-59011459200000),""Price"":0,""Sizes"":null}]",
+ Assert.AreEqual(@"[{""Name"":""Test1"",""Expiry"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null},{""Name"":""Test2"",""Expiry"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null},{""Name"":""Test3"",""Expiry"":""\/Date(946684800000)\/"",""Price"":0,""Sizes"":null}]",
sw.GetStringBuilder().ToString());
ProductCollection collectionNew = (ProductCollection)jsonSerializer.Deserialize(new JsonReader(new StringReader(sw.GetStringBuilder().ToString())), typeof(ProductCollection));
@@ -687,13 +748,18 @@ keyword such as type of business."" StringWriter sw = new StringWriter();
jsonSerializer.Serialize(sw, s1);
- Assert.AreEqual(@"{""Color"":2,""Establised"":new Date(1264118400000),""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""Expiry"":new Date(949532490000),""Price"":0},{""Name"":""Alien"",""Expiry"":new Date(-59011459200000),""Price"":0}]}", sw.GetStringBuilder().ToString());
+ //JavaScriptConvert.ConvertDateTimeToJavaScriptTicks(s1.Establised.DateTime)
+
+ Assert.AreEqual(@"{""Color"":2,""Establised"":""\/Date(1264122061000+0000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""Expiry"":""\/Date(949532490000)\/"",""Price"":0},{""Name"":""Alien"",""Expiry"":""\/Date(946684800000)\/"",""Price"":0}]}", sw.GetStringBuilder().ToString());
Store s2 = (Store)jsonSerializer.Deserialize(new JsonReader(new StringReader("{}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s2.Escape);
Store s3 = (Store)jsonSerializer.Deserialize(new JsonReader(new StringReader(@"{""Escape"":null}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s3.Escape);
+
+ Store s4 = (Store)jsonSerializer.Deserialize(new JsonReader(new StringReader(@"{""Color"":2,""Establised"":""\/Date(1264071600000+1300)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""Expiry"":""\/Date(949485690000+1300)\/"",""Price"":0},{""Name"":""Alien"",""Expiry"":""\/Date(946638000000)\/"",""Price"":0}]}")), typeof(Store));
+ Assert.AreEqual(s1.Establised, s3.Establised);
}
}
}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs index 5bb8aeb..4ca2273 100644 --- a/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonWriterTest.cs @@ -32,8 +32,7 @@ using System.IO; namespace Newtonsoft.Json.Tests
{
- [TestFixture]
- public class JsonWriterTest
+ public class JsonWriterTest : TestFixtureBase
{
[Test]
public void ValueFormatting()
diff --git a/Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs index 21df18f..9426abc 100644 --- a/Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs +++ b/Src/Newtonsoft.Json.Tests/LinqToJsonTest.cs @@ -34,8 +34,7 @@ using System.IO; namespace Newtonsoft.Json.Tests
{
- [TestFixture]
- public class LinqToJsonTest
+ public class LinqToJsonTest : TestFixtureBase
{
[Test]
public void ObjectParse()
@@ -226,12 +225,16 @@ keyword such as type of business."" [Test]
public void JTokenToStringTypes()
{
- string json = @"{""Color"":2,""Establised"":new Date(1264118400000),""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""Expiry"":new Date(949532490000),""Price"":0},{""Name"":""Alien"",""Expiry"":new Date(-59011459200000),""Price"":0}]}";
+ string json = @"{""Color"":2,""Establised"":new Date(1264118400000),""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""Expiry"":new Date(949532490000),""Price"":0},{""Name"":""Alien"",""Expiry"":new Date(-62135596800000),""Price"":0}]}";
JObject o = JObject.Parse(json);
- Assert.AreEqual(@"""Establised"": new Date(1264118400000)", o.Property("Establised").ToString());
- Assert.AreEqual(@"new Date(1264118400000)", o.Property("Establised").Value.ToString());
+ Assert.AreEqual(@"""Establised"": new Date(
+ 1264118400000
+)", o.Property("Establised").ToString());
+ Assert.AreEqual(@"new Date(
+ 1264118400000
+)", o.Property("Establised").Value.ToString());
Assert.AreEqual(@"""Width"": 1.1", o.Property("Width").ToString());
Assert.AreEqual(@"1.1", o.Property("Width").Value.ToString());
Assert.AreEqual(@"""Open"": false", o.Property("Open").ToString());
@@ -271,13 +274,13 @@ keyword such as type of business."" JArray a =
new JArray(
o,
- new DateTime(2000, 10, 10),
+ new DateTime(2000, 10, 10, 0, 0, 0, DateTimeKind.Utc),
55,
new JArray(
"1",
2,
3.0,
- new DateTime(4, 5, 6, 7, 8, 9)
+ new DateTime(4, 5, 6, 7, 8, 9, DateTimeKind.Utc)
),
new JConstructor(
"ConstructorName",
@@ -295,13 +298,13 @@ keyword such as type of business."" ""Test3"": ""Test3Value"",
""Test4"": null
},
- new Date(971136000000),
+ ""\/Date(971136000000)\/"",
55,
[
""1"",
2,
3,
- new Date(-59011459200000)
+ ""\/Date(-62030076711000)\/""
],
new ConstructorName(
""param1"",
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index c66a51e..2af957f 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -60,16 +60,23 @@ <Reference Include="System.ServiceModel.Web">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
+ <Reference Include="System.Web.Extensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="AspNetAjaxDateTimeConverterTest.cs" />
+ <Compile Include="DateTimeTestClass.cs" />
+ <Compile Include="IsoDateTimeConverterTests.cs" />
<Compile Include="JavaScriptConvertTest.cs" />
+ <Compile Include="JavaScriptDateTimeConverterTests.cs" />
<Compile Include="JsonReaderTest.cs" />
<Compile Include="JsonSerializerTest.cs" />
<Compile Include="JsonWriterTest.cs" />
<Compile Include="LinqToJsonTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="TestFixtureBase.cs" />
+ <Compile Include="UtcDateTimeConverterTest.cs" />
<Compile Include="XmlNodeConverterTest.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs new file mode 100644 index 0000000..6b0b9a9 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs @@ -0,0 +1,19 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace Newtonsoft.Json.Tests
+{
+ [TestFixture]
+ public abstract class TestFixtureBase
+ {
+ public string GetOffset(DateTime value)
+ {
+ TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime());
+
+ return utcOffset.Hours.ToString("+00;-00") + utcOffset.Minutes.ToString("00;00");
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs b/Src/Newtonsoft.Json.Tests/UtcDateTimeConverterTest.cs index eaaf83f..b71eb96 100644 --- a/Src/Newtonsoft.Json/Converters/AspNetAjaxDateTimeConverter.cs +++ b/Src/Newtonsoft.Json.Tests/UtcDateTimeConverterTest.cs @@ -23,37 +23,26 @@ // OTHER DEALINGS IN THE SOFTWARE.
#endregion
-
using System;
using System.Collections.Generic;
using System.Text;
+using NUnit.Framework;
+using Newtonsoft.Json;
+using System.IO;
+using Newtonsoft.Json.Converters;
+using System.Xml;
using System.Globalization;
-namespace Newtonsoft.Json.Converters
+namespace Newtonsoft.Json.Tests
{
- public class AspNetAjaxDateTimeConverter : JsonConverter
+ public class IsoDateTimeConverterTest : TestFixtureBase
{
- public override void WriteJson(JsonWriter writer, object value)
- {
- DateTime dateTime = (DateTime)value;
- long javaScriptTicks = JavaScriptConvert.ConvertDateTimeToJavaScriptTicks(dateTime);
-
- writer.WriteValue("@" + javaScriptTicks.ToString(null, CultureInfo.InvariantCulture) + "@");
- }
-
- public override object ReadJson(JsonReader reader, Type objectType)
- {
- string dateTimeText = (string)reader.Value;
- dateTimeText = dateTimeText.Substring(1, dateTimeText.Length - 2);
-
- long javaScriptTicks = Convert.ToInt64(dateTimeText);
-
- return JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
- }
-
- public override bool CanConvert(Type valueType)
+ [Test]
+ public void ShouldBeAbleToConvertDateTimes()
{
- return typeof(DateTime).IsAssignableFrom(valueType);
+ IsoDateTimeConverter conv = new IsoDateTimeConverter();
+ Assert.IsTrue(conv.CanConvert(typeof(DateTime)));
+ Assert.IsTrue(conv.CanConvert(typeof(DateTimeOffset)));
}
}
-}
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs index 21b4bcd..65ef870 100644 --- a/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/XmlNodeConverterTest.cs @@ -29,11 +29,11 @@ using Newtonsoft.Json; using System.IO;
using System.Xml;
using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Tests
{
- [TestFixture]
- public class XmlNodeConverterTest
+ public class XmlNodeConverterTest : TestFixtureBase
{
[Test]
public void DocumentSerializeIndented()
@@ -210,7 +210,7 @@ namespace Newtonsoft.Json.Tests string jsonText = JavaScriptConvert.SerializeXmlNode(doc);
- XmlDocument deserializedDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText);
+ XmlDocument deserializedDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(jsonText);
Assert.AreEqual(doc.InnerXml, deserializedDoc.InnerXml);
@@ -242,7 +242,7 @@ namespace Newtonsoft.Json.Tests }
}";
- XmlDocument doc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText);
+ XmlDocument doc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(jsonText);
string expected = @"<?xml version=""1.0"" standalone=""no""?>
<span class=""vevent"">
@@ -295,7 +295,7 @@ namespace Newtonsoft.Json.Tests string jsonText = JavaScriptConvert.SerializeXmlNode(doc);
- XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText);
+ XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(jsonText);
Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
}
@@ -322,7 +322,7 @@ namespace Newtonsoft.Json.Tests Console.WriteLine(jsonText);
- XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText);
+ XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(jsonText);
Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
}
@@ -330,13 +330,89 @@ namespace Newtonsoft.Json.Tests [Test]
public void OtherElementDataTypes()
{
- string jsonText = @"{""?xml"":{""@version"":""1.0"",""@standalone"":""no""},""root"":{""person"":[{""@id"":""1"",""Float"":2.5,""Integer"":99},{""@id"":""2"",""Boolean"":true,""date"":new Date(954374400000)}]}}";
+ string jsonText = @"{""?xml"":{""@version"":""1.0"",""@standalone"":""no""},""root"":{""person"":[{""@id"":""1"",""Float"":2.5,""Integer"":99},{""@id"":""2"",""Boolean"":true,""date"":""\/Date(954374400000)\/""}]}}";
- XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeerializeXmlNode(jsonText);
+ XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(jsonText);
- string expected = @"<?xml version=""1.0"" standalone=""no""?><root><person id=""1""><Float>2.5</Float><Integer>99</Integer></person><person id=""2""><Boolean>true</Boolean><date>2000-03-30T00:00:00.0000000+13:00</date></person></root>";
+ string expected = @"<?xml version=""1.0"" standalone=""no""?><root><person id=""1""><Float>2.5</Float><Integer>99</Integer></person><person id=""2""><Boolean>true</Boolean><date>2000-03-30T00:00:00Z</date></person></root>";
Assert.AreEqual(expected, newDoc.InnerXml);
}
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "XmlNodeConverter can only convert JSON that begins with an object.")]
+ public void NoRootObject()
+ {
+ XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(@"[1]");
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties.")]
+ public void RootObjectMultipleProperties()
+ {
+ XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(@"{Prop1:1,Prop2:2}");
+ }
+
+ [Test]
+ public void JavaScriptConstructor()
+ {
+ string jsonText = @"{root:{r:new Date(34343, 55)}}";
+
+ XmlDocument newDoc = (XmlDocument)JavaScriptConvert.DeserializeXmlNode(jsonText);
+
+ string expected = @"<root><r><-Date>34343</-Date><-Date>55</-Date></r></root>";
+
+ Assert.AreEqual(expected, newDoc.InnerXml);
+
+ string json = JavaScriptConvert.SerializeXmlNode(newDoc);
+ Assert.AreEqual(@"{""root"":{""r"":new Date(""34343"",""55"")}}", json);
+ }
+
+ [Test]
+ public void ForceJsonArray()
+ {
+ string arrayXml = @"<root xmlns:json=""http://james.newtonking.com/projects/json"">
+ <person id=""1"">
+ <name>Alan</name>
+ <url>http://www.google.com</url>
+ <role json:Array=""true"">Admin</role>
+ </person>
+ </root>";
+
+ XmlDocument arrayDoc = new XmlDocument();
+ arrayDoc.LoadXml(arrayXml);
+
+ string arrayJsonText = JavaScriptConvert.SerializeXmlNode(arrayDoc);
+ Assert.AreEqual(@"{""root"":{""person"":{""@id"":""1"",""name"":""Alan"",""url"":""http://www.google.com"",""role"":[""Admin""]}}}", arrayJsonText);
+
+ arrayXml = @"<root xmlns:json=""http://james.newtonking.com/projects/json"">
+ <person id=""1"">
+ <name>Alan</name>
+ <url>http://www.google.com</url>
+ <role json:Array=""true"">Admin1</role>
+ <role json:Array=""true"">Admin2</role>
+ </person>
+ </root>";
+
+ arrayDoc = new XmlDocument();
+ arrayDoc.LoadXml(arrayXml);
+
+ arrayJsonText = JavaScriptConvert.SerializeXmlNode(arrayDoc);
+ Assert.AreEqual(@"{""root"":{""person"":{""@id"":""1"",""name"":""Alan"",""url"":""http://www.google.com"",""role"":[""Admin1"",""Admin2""]}}}", arrayJsonText);
+
+ arrayXml = @"<root xmlns:json=""http://james.newtonking.com/projects/json"">
+ <person id=""1"">
+ <name>Alan</name>
+ <url>http://www.google.com</url>
+ <role json:Array=""false"">Admin1</role>
+ </person>
+ </root>";
+
+ arrayDoc = new XmlDocument();
+ arrayDoc.LoadXml(arrayXml);
+
+ arrayJsonText = JavaScriptConvert.SerializeXmlNode(arrayDoc);
+ Assert.AreEqual(@"{""root"":{""person"":{""@id"":""1"",""name"":""Alan"",""url"":""http://www.google.com"",""role"":""Admin1""}}}", arrayJsonText);
+ }
}
}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs new file mode 100644 index 0000000..8d06729 --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs @@ -0,0 +1,74 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Globalization;
+
+namespace Newtonsoft.Json.Converters
+{
+ public class IsoDateTimeConverter : JsonConverter
+ {
+ private const string DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";
+
+ private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind;
+ //private bool _forceUniversalTime;
+
+ //public bool ForceUniversalTime
+ //{
+ // get { return _forceUniversalTime; }
+ // set { _forceUniversalTime = value; }
+ //}
+
+ public DateTimeStyles DateTimeStyles
+ {
+ get { return _dateTimeStyles; }
+ set { _dateTimeStyles = value; }
+ }
+
+ public override void WriteJson(JsonWriter writer, object value)
+ {
+ string text;
+
+ if (value is DateTime)
+ {
+ DateTime dateTime = (DateTime)value;
+
+ if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
+ || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
+ dateTime = dateTime.ToUniversalTime();
+
+ text = dateTime.ToString(DateTimeFormat, CultureInfo.InvariantCulture);
+ }
+ else
+ {
+ DateTimeOffset dateTimeOffset = (DateTimeOffset)value;
+ if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
+ || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
+ dateTimeOffset = dateTimeOffset.ToUniversalTime();
+
+ text = dateTimeOffset.ToString(DateTimeFormat, CultureInfo.InvariantCulture);
+ }
+
+ writer.WriteValue(text);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType)
+ {
+ if (reader.TokenType != JsonToken.String)
+ throw new Exception(string.Format("Unexpected token parsing date. Expected String, got {0}.", reader.TokenType));
+
+ string dateText = reader.Value.ToString();
+
+ if (objectType == typeof(DateTimeOffset))
+ return DateTimeOffset.Parse(dateText, CultureInfo.InvariantCulture, _dateTimeStyles);
+
+ return DateTime.Parse(dateText, CultureInfo.InvariantCulture, _dateTimeStyles);
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return (typeof(DateTime).IsAssignableFrom(objectType)
+ || typeof(DateTimeOffset).IsAssignableFrom(objectType));
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs new file mode 100644 index 0000000..e74698c --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -0,0 +1,64 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Globalization;
+
+namespace Newtonsoft.Json.Converters
+{
+ public class JavaScriptDateTimeConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value)
+ {
+ long ticks;
+
+ if (value is DateTime)
+ {
+ DateTime dateTime = (DateTime)value;
+ DateTime utcDateTime = dateTime.ToUniversalTime();
+ ticks = JavaScriptConvert.ConvertDateTimeToJavaScriptTicks(utcDateTime);
+ }
+ else
+ {
+ DateTimeOffset dateTimeOffset = (DateTimeOffset)value;
+ DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime();
+ ticks = JavaScriptConvert.ConvertDateTimeToJavaScriptTicks(utcDateTimeOffset.UtcDateTime);
+ }
+
+ writer.WriteStartConstructor("Date");
+ writer.WriteValue(ticks);
+ writer.WriteEndConstructor();
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType)
+ {
+ if (reader.TokenType != JsonToken.StartConstructor || string.Compare(reader.Value.ToString(), "Date", StringComparison.Ordinal) != 0)
+ throw new Exception(string.Format("Unexpected token or value when parsing date. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
+
+ reader.Read();
+
+ if (reader.TokenType != JsonToken.Integer)
+ throw new Exception(string.Format("Unexpected token parsing date. Expected Integer, got {0}.", reader.TokenType));
+
+ long ticks = (long)reader.Value;
+
+ DateTime d = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(ticks);
+
+ reader.Read();
+
+ if (reader.TokenType != JsonToken.EndConstructor)
+ throw new Exception(string.Format("Unexpected token parsing date. Expected EndConstructor, got {0}.", reader.TokenType));
+
+ if (objectType == typeof(DateTimeOffset))
+ return new DateTimeOffset(d);
+
+ return d;
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return (typeof(DateTime).IsAssignableFrom(objectType)
+ || typeof(DateTimeOffset).IsAssignableFrom(objectType));
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs b/Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs new file mode 100644 index 0000000..4b9f310 --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs @@ -0,0 +1,15 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Converters
+{
+ public enum JsonDateTimeSerializationMode
+ {
+ Local,
+ Utc,
+ Unspecified,
+ RoundtripKind
+ }
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 3c5a7ad..0ff6a1f 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -29,6 +29,7 @@ using System.Text; using System.Drawing;
using System.Xml;
using Newtonsoft.Json.Utilities;
+using System.Linq;
namespace Newtonsoft.Json.Converters
{
@@ -40,6 +41,7 @@ namespace Newtonsoft.Json.Converters private const string WhitespaceName = "#whitespace";
private const string SignificantWhitespaceName = "#significant-whitespace";
private const string DeclarationName = "?xml";
+ private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
#region Writing
public override void WriteJson(JsonWriter writer, object value)
@@ -106,13 +108,29 @@ namespace Newtonsoft.Json.Converters foreach (KeyValuePair<string, List<XmlNode>> nodeNameGroup in nodesGroupedByName)
{
List<XmlNode> groupedNodes = nodeNameGroup.Value;
+ bool writeArray;
if (groupedNodes.Count == 1)
{
+ XmlNode singleNode = groupedNodes[0];
+ XmlAttribute jsonArrayAttribute = (singleNode.Attributes != null) ? singleNode.Attributes["Array", JsonNamespaceUri] : null;
+ if (jsonArrayAttribute != null)
+ writeArray = XmlConvert.ToBoolean(jsonArrayAttribute.Value);
+ else
+ writeArray = false;
+ }
+ else
+ {
+ writeArray = true;
+ }
+
+ if (!writeArray)
+ {
SerializeNode(writer, groupedNodes[0], true);
}
else
{
+ string elementNames = nodeNameGroup.Key;
writer.WritePropertyName(nodeNameGroup.Key);
writer.WriteStartArray();
@@ -138,7 +156,7 @@ namespace Newtonsoft.Json.Converters if (writePropertyName)
writer.WritePropertyName(node.Name);
- if (CollectionUtils.IsNullOrEmpty(node.Attributes) && node.ChildNodes.Count == 1
+ if (ValueAttributes(node.Attributes).Count() == 0 && node.ChildNodes.Count == 1
&& node.ChildNodes[0].NodeType == XmlNodeType.Text)
{
// write elements with a single text child as a name value pair
@@ -149,6 +167,20 @@ namespace Newtonsoft.Json.Converters // empty element
writer.WriteNull();
}
+ else if (node.ChildNodes.OfType<XmlElement>().Where(x => x.Name.StartsWith("-")).Count() > 1)
+ {
+ XmlElement constructorValueElement = node.ChildNodes.OfType<XmlElement>().Where(x => x.Name.StartsWith("-")).First();
+ string constructorName = constructorValueElement.Name.Substring(1);
+
+ writer.WriteStartConstructor(constructorName);
+
+ for (int i = 0; i < node.ChildNodes.Count; i++)
+ {
+ SerializeNode(writer, node.ChildNodes[i], false);
+ }
+
+ writer.WriteEndConstructor();
+ }
else
{
writer.WriteStartObject();
@@ -174,6 +206,11 @@ namespace Newtonsoft.Json.Converters case XmlNodeType.ProcessingInstruction:
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
+ if (node.Prefix == "xmlns" && node.Value == JsonNamespaceUri)
+ break;
+ else if (node.NamespaceURI == JsonNamespaceUri)
+ break;
+
if (writePropertyName)
writer.WritePropertyName(GetPropertyName(node));
writer.WriteValue(node.Value);
@@ -216,6 +253,10 @@ namespace Newtonsoft.Json.Converters XmlDocument document = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
+
+ if (reader.TokenType != JsonToken.StartObject)
+ throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
+
reader.Read();
DeserializeNode(reader, document, manager, document);
@@ -241,7 +282,7 @@ namespace Newtonsoft.Json.Converters break;
default:
// processing instructions and the xml declaration start with ?
- if (propertyName[0] == '?')
+ if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
{
if (propertyName == DeclarationName)
{
@@ -292,7 +333,8 @@ namespace Newtonsoft.Json.Converters && reader.TokenType != JsonToken.Boolean
&& reader.TokenType != JsonToken.Integer
&& reader.TokenType != JsonToken.Float
- && reader.TokenType != JsonToken.Date)
+ && reader.TokenType != JsonToken.Date
+ && reader.TokenType != JsonToken.StartConstructor)
{
// read properties until first non-attribute is encountered
while (!finishedAttributes && !finishedElement && reader.Read())
@@ -370,7 +412,8 @@ namespace Newtonsoft.Json.Converters }
else if (reader.TokenType == JsonToken.Date)
{
- element.AppendChild(document.CreateTextNode(XmlConvert.ToString((DateTime)reader.Value)));
+ DateTime d = (DateTime)reader.Value;
+ element.AppendChild(document.CreateTextNode(XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind))));
}
else if (reader.TokenType == JsonToken.Null)
{
@@ -400,6 +443,9 @@ namespace Newtonsoft.Json.Converters switch (reader.TokenType)
{
case JsonToken.PropertyName:
+ if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
+ throw new JsonSerializationException("JSON root object has multiple properties.");
+
string propertyName = reader.Value.ToString();
reader.Read();
@@ -415,6 +461,14 @@ namespace Newtonsoft.Json.Converters DeserializeValue(reader, document, manager, propertyName, currentNode);
}
break;
+ case JsonToken.StartConstructor:
+ string constructorName = reader.Value.ToString();
+
+ while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
+ {
+ DeserializeValue(reader, document, manager, "-" + constructorName, currentNode);
+ }
+ break;
case JsonToken.EndObject:
case JsonToken.EndArray:
return;
@@ -459,6 +513,16 @@ namespace Newtonsoft.Json.Converters else
return qualifiedName.Substring(0, colonPosition);
}
+
+ private IEnumerable<XmlAttribute> ValueAttributes(XmlAttributeCollection c)
+ {
+ return c.OfType<XmlAttribute>().Where(a => a.NamespaceURI != JsonNamespaceUri);
+ }
+
+ private IEnumerable<XmlNode> ValueNodes(XmlNodeList c)
+ {
+ return c.OfType<XmlNode>().Where(n => n.NamespaceURI != JsonNamespaceUri);
+ }
#endregion
public override bool CanConvert(Type valueType)
diff --git a/Src/Newtonsoft.Json/JavaScriptConvert.cs b/Src/Newtonsoft.Json/JavaScriptConvert.cs index ea1f7df..5bb4638 100644 --- a/Src/Newtonsoft.Json/JavaScriptConvert.cs +++ b/Src/Newtonsoft.Json/JavaScriptConvert.cs @@ -75,7 +75,7 @@ namespace Newtonsoft.Json Null = "null";
Undefined = "undefined";
- InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1)).Ticks;
+ InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Ticks;
MinimumJavaScriptDate = new DateTime(100, 1, 1);
}
@@ -86,24 +86,53 @@ namespace Newtonsoft.Json /// <returns>A Json string representation of the <see cref="DateTime"/>.</returns>
public static string ToString(DateTime value)
{
+ return ToStringInternal(new DateTimeOffset(value), value.Kind);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="DateTimeOffset"/> to it's JavaScript string representation.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <returns>A Json string representation of the <see cref="DateTimeOffset"/>.</returns>
+ public static string ToString(DateTimeOffset value)
+ {
+ return ToStringInternal(value, DateTimeKind.Local);
+ }
+
+ public static string ToStringInternal(DateTimeOffset value, DateTimeKind kind)
+ {
long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value);
- return "new Date(" + javaScriptTicks + ")";
+ string offset;
+ switch (kind)
+ {
+ case DateTimeKind.Local:
+ case DateTimeKind.Unspecified:
+ TimeSpan utcOffset = value.Offset;
+ offset = utcOffset.Hours.ToString("+00;-00") + utcOffset.Minutes.ToString("00;00");
+ break;
+ default:
+ offset = string.Empty;
+ break;
+ }
+ return @"""\/Date(" + javaScriptTicks.ToString(CultureInfo.InvariantCulture) + offset + @")\/""";
}
- internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime)
+ internal static long ConvertDateTimeToJavaScriptTicks(DateTimeOffset dateTime)
{
- if (dateTime < MinimumJavaScriptDate)
- dateTime = MinimumJavaScriptDate;
+ DateTimeOffset utcDateTime = dateTime.ToUniversalTime();
- long javaScriptTicks = (dateTime.Ticks - InitialJavaScriptDateTicks) / (long)10000;
+ //if (utcDateTime < MinimumJavaScriptDate)
+ // utcDateTime = MinimumJavaScriptDate;
+
+ long javaScriptTicks = (utcDateTime.Ticks - InitialJavaScriptDateTicks) / (long)10000;
return javaScriptTicks;
}
internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks)
{
- DateTime dateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks);
+ DateTime dateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc);
return dateTime;
}
@@ -328,6 +357,10 @@ namespace Newtonsoft.Json return ToString((decimal)convertible);
}
}
+ else if (value is DateTimeOffset)
+ {
+ return ToString((DateTimeOffset)value);
+ }
throw new ArgumentException(string.Format("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.", value.GetType()));
}
@@ -397,12 +430,28 @@ namespace Newtonsoft.Json }
/// <summary>
+ /// Deserializes the specified JSON to the given anonymous type.
+ /// </summary>
+ /// <typeparam name="T">
+ /// The anonymous type to deserialize to. This can't be specified
+ /// traditionally and must be infered from the anonymous type passed
+ /// as a parameter.
+ /// </typeparam>
+ /// <param name="value">The object to deserialize.</param>
+ /// <param name="anonymousTypeObject">The anonymous type object.</param>
+ /// <returns>The deserialized anonymous type from the JSON string.</returns>
+ public static T DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
+ {
+ return (T)DeserializeObject(value, typeof(T));
+ }
+
+ /// <summary>
/// Deserializes the specified object to a Json object.
/// </summary>
/// <typeparam name="T">The type of the object to deserialize.</typeparam>
/// <param name="value">The object to deserialize.</param>
/// <param name="converters">Converters to use while deserializing.</param>
- /// <returns>The deserialized object from the Json string.</returns>
+ /// <returns>The deserialized object from the JSON string.</returns>
public static T DeserializeObject<T>(string value, params JsonConverter[] converters)
{
return (T)DeserializeObject(value, typeof(T), converters);
@@ -438,7 +487,7 @@ namespace Newtonsoft.Json return SerializeObject(node, converter);
}
- public static XmlNode DeerializeXmlNode(string value)
+ public static XmlNode DeserializeXmlNode(string value)
{
XmlNodeConverter converter = new XmlNodeConverter();
diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs index bff625b..849f9be 100644 --- a/Src/Newtonsoft.Json/JsonConverter.cs +++ b/Src/Newtonsoft.Json/JsonConverter.cs @@ -40,9 +40,9 @@ namespace Newtonsoft.Json public virtual object ReadJson(JsonReader reader, Type objectType)
{
- throw new NotImplementedException(string.Format("{0} has not overriden FromJson method.", GetType().Name));
+ throw new NotImplementedException(string.Format("{0} has not overriden the ReadJson method.", GetType().Name));
}
public abstract bool CanConvert(Type objectType);
}
-}
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index db7181e..8421c2d 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -217,11 +217,54 @@ namespace Newtonsoft.Json ClearCurrentChar();
_currentState = State.PostValue;
- _token = JsonToken.String;
- _value = _buffer.ToString();
+ string text = _buffer.ToString();
_buffer.Position = 0;
- _valueType = typeof(string);
- _quoteChar = quote;
+
+ if (text.StartsWith("/Date(", StringComparison.Ordinal) && text.EndsWith(")/", StringComparison.Ordinal))
+ {
+ ParseDate(text);
+ }
+ else
+ {
+ SetToken(JsonToken.String, text);
+ _quoteChar = quote;
+ }
+ }
+
+ private void ParseDate(string text)
+ {
+ string value = text.Substring(6, text.Length - 8);
+ DateTimeKind kind = DateTimeKind.Utc;
+
+ int index = value.IndexOf('+', 1);
+
+ if (index == -1)
+ index = value.IndexOf('-', 1);
+
+ if (index != -1)
+ {
+ kind = DateTimeKind.Local;
+ value = value.Substring(0, index);
+ }
+
+ long javaScriptTicks = long.Parse(value);
+ DateTime utcDateTime = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
+ DateTime dateTime;
+
+ switch (kind)
+ {
+ case DateTimeKind.Unspecified:
+ dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
+ break;
+ case DateTimeKind.Local:
+ dateTime = utcDateTime.ToLocalTime();
+ break;
+ default:
+ dateTime = utcDateTime;
+ break;
+ }
+
+ SetToken(JsonToken.Date, dateTime);
}
private bool MoveNext()
@@ -648,22 +691,22 @@ namespace Newtonsoft.Json _value = constructorName;
_valueType = typeof(string);
- if (string.CompareOrdinal(constructorName, "Date") == 0)
- {
- IList<object> parameters = new List<object>();
+ //if (string.CompareOrdinal(constructorName, "Date") == 0)
+ //{
+ // IList<object> parameters = new List<object>();
- MoveNext();
- while (ParseValue() && _token != JsonToken.EndConstructor)
- {
- parameters.Add(_value);
- }
+ // MoveNext();
+ // while (ParseValue() && _token != JsonToken.EndConstructor)
+ // {
+ // parameters.Add(_value);
+ // }
- long javaScriptTicks = Convert.ToInt64(parameters[0]);
+ // long javaScriptTicks = Convert.ToInt64(parameters[0]);
- DateTime date = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
+ // DateTime date = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
- SetToken(JsonToken.Date, date);
- }
+ // SetToken(JsonToken.Date, date);
+ //}
@@ -754,6 +797,9 @@ namespace Newtonsoft.Json case JsonType.Array:
_currentState = State.Array;
break;
+ case JsonType.Constructor:
+ _currentState = State.Constructor;
+ break;
case JsonType.None:
_currentState = State.Finished;
break;
diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index 55243ed..359ed71 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -32,6 +32,7 @@ using System.Reflection; using System.ComponentModel;
using Newtonsoft.Json.Utilities;
using System.Globalization;
+using System.Linq;
namespace Newtonsoft.Json
{
@@ -233,11 +234,7 @@ namespace Newtonsoft.Json case JsonToken.EndConstructor:
string constructorName = reader.Value.ToString();
- //if (string.CompareOrdinal(constructorName, "Date") == 0)
- // value = CreateDate(reader);
- //else
- //TODO: use objectType plus constructor arguments to instantiate object
- value = constructorName;
+ value = constructorName;
break;
case JsonToken.Null:
case JsonToken.Undefined:
@@ -298,12 +295,15 @@ namespace Newtonsoft.Json return targetConverter.ConvertFromInvariantString(valueString);
}
+ if (targetType == typeof(DateTimeOffset) && value is DateTime)
+ return new DateTimeOffset((DateTime)value);
+
if (!targetType.IsAssignableFrom(valueType))
throw new InvalidOperationException(string.Format("Cannot convert object of type '{0}' to type '{1}'", value.GetType(), targetType));
return value;
}
-
+
return targetConverter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
}
else
@@ -343,7 +343,7 @@ namespace Newtonsoft.Json else
mappedName = member.Name;
- bool ignored = member.IsDefined(typeof (JsonIgnoreAttribute), true);
+ bool ignored = member.IsDefined(typeof(JsonIgnoreAttribute), true);
bool readable = ReflectionUtils.CanReadMemberValue(member);
bool writable = ReflectionUtils.CanSetMemberValue(member);
MemberMapping memberMapping = new MemberMapping(mappedName, member, ignored, readable, writable);
@@ -409,50 +409,102 @@ namespace Newtonsoft.Json Type elementType = ReflectionUtils.GetListItemType(objectType);
IList populatedList = CollectionUtils.CreateAndPopulateList(objectType, delegate(IList list)
+ {
+ while (reader.Read())
{
- while (reader.Read())
+ switch (reader.TokenType)
{
- switch (reader.TokenType)
- {
- case JsonToken.EndArray:
- return;
- case JsonToken.Comment:
- break;
- default:
- object value = GetObject(reader, elementType);
-
- list.Add(value);
- break;
- }
+ case JsonToken.EndArray:
+ return;
+ case JsonToken.Comment:
+ break;
+ default:
+ object value = GetObject(reader, elementType);
+
+ list.Add(value);
+ break;
}
+ }
- throw new JsonSerializationException("Unexpected end when deserializing array.");
- });
+ throw new JsonSerializationException("Unexpected end when deserializing array.");
+ });
return populatedList;
}
private object PopulateObject(JsonReader reader, Type objectType)
{
- object newObject = Activator.CreateInstance(objectType);
+ object newObject;
- while (reader.Read())
+ if (ReflectionUtils.HasDefaultConstructor(objectType))
{
- switch (reader.TokenType)
+ newObject = Activator.CreateInstance(objectType);
+
+ while (reader.Read())
{
- case JsonToken.PropertyName:
- string memberName = reader.Value.ToString();
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string memberName = reader.Value.ToString();
- SetObjectMember(reader, newObject, objectType, memberName);
- break;
- case JsonToken.EndObject:
- return newObject;
- default:
- throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ SetObjectMember(reader, newObject, objectType, memberName);
+ break;
+ case JsonToken.EndObject:
+ return newObject;
+ default:
+ throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ }
}
+
+ throw new JsonSerializationException("Unexpected end when deserializing object.");
}
+ else
+ {
+ ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
+
+ if (c == null)
+ throw new Exception("sdsdf");
+
+ IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
+ //IList<object> constructorValues
+
+ bool exit = false;
+ while (!exit && reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string memberName = reader.Value.ToString();
+ ParameterInfo matchingConstructorParameter = constructorParameters
+ .Where(kv => kv.Key.Name == memberName)
+ .Select(kv => kv.Key)
+ .SingleOrDefault();
+
+ if (!reader.Read())
+ throw new JsonSerializationException(string.Format("Unexpected end when setting {0}'s value.", memberName));
+
+
+ if (matchingConstructorParameter != null)
+ {
+ constructorParameters[matchingConstructorParameter] = GetObject(reader, matchingConstructorParameter.ParameterType);
+ }
+
- throw new JsonSerializationException("Unexpected end when deserializing object.");
+
+ //SetObjectMember(reader, newObject, objectType, memberName);
+ break;
+ case JsonToken.EndObject:
+ exit = true;
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ }
+ }
+
+ newObject = Activator.CreateInstance(objectType, constructorParameters.Values.ToArray());
+
+ return newObject;
+ }
}
#endregion
@@ -554,6 +606,10 @@ namespace Newtonsoft.Json break;
}
}
+ else if (value is DateTimeOffset)
+ {
+ writer.WriteValue((DateTimeOffset)value);
+ }
else if (value is IList)
{
SerializeList(writer, (IList)value);
@@ -694,4 +750,4 @@ namespace Newtonsoft.Json }
#endregion
}
-}
+}
\ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 953f198..f488e6b 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -724,6 +724,15 @@ namespace Newtonsoft.Json {
WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Date);
}
+
+ /// <summary>
+ /// Writes a <see cref="DateTimeOffset"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
+ public void WriteValue(DateTimeOffset value)
+ {
+ WriteValueInternal(JavaScriptConvert.ToString(value), JsonToken.Date);
+ }
#endregion
/// <summary>
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 51fb364..530039e 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -73,7 +73,9 @@ <Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="Converters\AspNetAjaxDateTimeConverter.cs" />
+ <Compile Include="Converters\IsoDateTimeConverter.cs" />
+ <Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
+ <Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
<Compile Include="Converters\XmlNodeConverter.cs" />
<Compile Include="Converters\HtmlColorConverter.cs" />
<Compile Include="JavaScriptParameters.cs" />
@@ -105,6 +107,7 @@ <Compile Include="MissingMemberHandling.cs" />
<Compile Include="NullValueHandling.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
+ <Compile Include="Utilities\DateTimeUtils.cs" />
<Compile Include="Utilities\JavaScriptUtils.cs" />
<Compile Include="JsonToken.cs" />
<Compile Include="JsonWriter.cs" />
diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs new file mode 100644 index 0000000..4ba824a --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs @@ -0,0 +1,33 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace Newtonsoft.Json.Utilities
+{
+ public static class DateTimeUtils
+ {
+ public static string GetLocalOffset(this DateTime d)
+ {
+ TimeSpan utcOffset = TimeZoneInfo.Local.GetUtcOffset(d);
+
+ return utcOffset.Hours.ToString("+00;-00") + ":" + utcOffset.Minutes.ToString("00;00");
+ }
+
+ public static XmlDateTimeSerializationMode ToSerializationMode(DateTimeKind kind)
+ {
+ switch (kind)
+ {
+ case DateTimeKind.Local:
+ return XmlDateTimeSerializationMode.Local;
+ case DateTimeKind.Unspecified:
+ return XmlDateTimeSerializationMode.Unspecified;
+ case DateTimeKind.Utc:
+ return XmlDateTimeSerializationMode.Utc;
+ default:
+ throw new ArgumentOutOfRangeException("kind", kind, "Unexpected DateTimeKind value.");
+ }
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index c6084c3..79a2170 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -545,4 +545,4 @@ namespace Newtonsoft.Json.Utilities return Activator.CreateInstance(specificType, args);
}
}
-}
+}
\ No newline at end of file |