diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
index 1aa6a1ab..e6cd9619 100644
--- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
@@ -512,6 +512,17 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.AreEqual(@"113150assets/images/resized/0001/1070/11070v1-max-150x150.jpg189250assets/images/resized/0001/1070/11070v1-max-250x250.jpg341450assets/images/resized/0001/1070/11070v1-max-450x450.jpg", newDoc.InnerXml);
}
+
+ [Test]
+ public void Encoding()
+ {
+ XmlDocument doc = new XmlDocument();
+
+ doc.LoadXml(@"O""Connor"); // i use "" so it will be easier to see the problem
+
+ string json = JsonConvert.SerializeXmlNode(doc);
+ Assert.AreEqual(@"{""name"":""O\""Connor""}", json);
+ }
}
}
#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/BindingTests.cs b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/BindingTests.cs
new file mode 100644
index 00000000..6ee97a10
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/BindingTests.cs
@@ -0,0 +1,79 @@
+#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
+
+#if !PocketPC && !SILVERLIGHT
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using System.Web.UI;
+using Newtonsoft.Json.Linq;
+
+namespace Newtonsoft.Json.Tests.Linq.ComponentModel
+{
+ public class BindingTests : TestFixtureBase
+ {
+ [Test]
+ public void DataBinderEval()
+ {
+ JObject o = new JObject(
+ new JProperty("First", "String!"),
+ new JProperty("Second", 12345.6789m),
+ new JProperty("Third", new JArray(
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ new JObject(
+ new JProperty("Fourth", "String!"),
+ new JProperty("Fifth", new JObject(
+ new JProperty("Sixth", "String!")))))));
+
+ object value;
+
+ value = DataBinder.Eval(o, "First");
+ Assert.AreEqual(value, (string)o["First"]);
+
+ value = DataBinder.Eval(o, "Second");
+ Assert.AreEqual(value, (decimal)o["Second"]);
+
+ value = DataBinder.Eval(o, "Third");
+ Assert.AreEqual(value, o["Third"]);
+
+ value = DataBinder.Eval(o, "Third[0]");
+ // urg!
+ Assert.AreEqual((int)(JToken)value, (int)o["Third"][0]);
+
+ value = DataBinder.Eval(o, "Third[5].Fourth");
+ Assert.AreEqual(value, (string)o["Third"][5]["Fourth"]);
+
+ value = DataBinder.Eval(o, "Third[5].Fifth.Sixth");
+ Assert.AreEqual(value, (string)o["Third"][5]["Fifth"]["Sixth"]);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs
new file mode 100644
index 00000000..4e82bb9b
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs
@@ -0,0 +1,91 @@
+#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
+
+#if !SILVERLIGHT
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Newtonsoft.Json.Linq.ComponentModel;
+using Newtonsoft.Json.Linq;
+
+namespace Newtonsoft.Json.Tests.Linq.ComponentModel
+{
+ public class JPropertyDescriptorTests : TestFixtureBase
+ {
+ [Test]
+ public void GetValue()
+ {
+ JObject o = JObject.Parse("{prop1:'12345!',prop2:[1,'two','III']}");
+
+ JPropertyDescriptor prop1 = new JPropertyDescriptor("prop1", typeof(string));
+ JPropertyDescriptor prop2 = new JPropertyDescriptor("prop2", typeof(JArray));
+
+ Assert.AreEqual("12345!", prop1.GetValue(o));
+ Assert.AreEqual(o["prop2"], prop2.GetValue(o));
+ }
+
+ [Test]
+ public void SetValue()
+ {
+ JObject o = JObject.Parse("{prop1:'12345!'}");
+
+ JPropertyDescriptor propertyDescriptor1 = new JPropertyDescriptor("prop1", typeof(string));
+
+ propertyDescriptor1.SetValue(o, "54321!");
+
+ Assert.AreEqual("54321!", (string)o["prop1"]);
+ }
+
+ [Test]
+ public void ResetValue()
+ {
+ JObject o = JObject.Parse("{prop1:'12345!'}");
+
+ JPropertyDescriptor propertyDescriptor1 = new JPropertyDescriptor("prop1", typeof(string));
+ propertyDescriptor1.ResetValue(o);
+
+ Assert.AreEqual("12345!", (string)o["prop1"]);
+ }
+
+ [Test]
+ public void IsReadOnly()
+ {
+ JPropertyDescriptor propertyDescriptor1 = new JPropertyDescriptor("prop1", typeof(string));
+
+ Assert.AreEqual(false, propertyDescriptor1.IsReadOnly);
+ }
+
+ [Test]
+ public void PropertyType()
+ {
+ JPropertyDescriptor propertyDescriptor1 = new JPropertyDescriptor("prop1", typeof(string));
+
+ Assert.AreEqual(typeof(string), propertyDescriptor1.PropertyType);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JTypeDescriptionProviderTests.cs b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JTypeDescriptionProviderTests.cs
new file mode 100644
index 00000000..1dafce03
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JTypeDescriptionProviderTests.cs
@@ -0,0 +1,49 @@
+#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
+
+#if !PocketPC && !SILVERLIGHT
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Newtonsoft.Json.Linq;
+using System.ComponentModel;
+using Newtonsoft.Json.Linq.ComponentModel;
+
+namespace Newtonsoft.Json.Tests.Linq.ComponentModel
+{
+ public class JTypeDescriptionProviderTests : TestFixtureBase
+ {
+ [Test]
+ public void GetTypeDescriptor()
+ {
+ JTypeDescriptionProvider provider = new JTypeDescriptionProvider();
+ JTypeDescriptor descriptor = (JTypeDescriptor)provider.GetTypeDescriptor(typeof (JObject), new JObject());
+ Assert.IsNotNull(descriptor);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JTypeDescriptorTests.cs b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JTypeDescriptorTests.cs
new file mode 100644
index 00000000..a7bfd71b
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JTypeDescriptorTests.cs
@@ -0,0 +1,80 @@
+#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
+
+#if !SILVERLIGHT
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json.Linq.ComponentModel;
+using NUnit.Framework;
+using Newtonsoft.Json.Linq;
+using System.ComponentModel;
+
+namespace Newtonsoft.Json.Tests.Linq.ComponentModel
+{
+ public class JTypeDescriptorTests : TestFixtureBase
+ {
+ [Test]
+ public void GetProperties()
+ {
+ JObject o = JObject.Parse("{'prop1':12,'prop2':'hi!','prop3':null,'prop4':[1,2,3]}");
+
+ JTypeDescriptor descriptor = new JTypeDescriptor(o);
+
+ PropertyDescriptorCollection properties = descriptor.GetProperties();
+ Assert.AreEqual(4, properties.Count);
+
+ PropertyDescriptor prop1 = properties[0];
+ Assert.AreEqual("prop1", prop1.Name);
+ Assert.AreEqual(typeof(long), prop1.PropertyType);
+ Assert.AreEqual(typeof(JObject), prop1.ComponentType);
+ Assert.AreEqual(false, prop1.CanResetValue(o));
+ Assert.AreEqual(false, prop1.ShouldSerializeValue(o));
+
+ PropertyDescriptor prop2 = properties[1];
+ Assert.AreEqual("prop2", prop2.Name);
+ Assert.AreEqual(typeof(string), prop2.PropertyType);
+ Assert.AreEqual(typeof(JObject), prop2.ComponentType);
+ Assert.AreEqual(false, prop2.CanResetValue(o));
+ Assert.AreEqual(false, prop2.ShouldSerializeValue(o));
+
+ PropertyDescriptor prop3 = properties[2];
+ Assert.AreEqual("prop3", prop3.Name);
+ Assert.AreEqual(typeof(object), prop3.PropertyType);
+ Assert.AreEqual(typeof(JObject), prop3.ComponentType);
+ Assert.AreEqual(false, prop3.CanResetValue(o));
+ Assert.AreEqual(false, prop3.ShouldSerializeValue(o));
+
+ PropertyDescriptor prop4 = properties[3];
+ Assert.AreEqual("prop4", prop4.Name);
+ Assert.AreEqual(typeof(JArray), prop4.PropertyType);
+ Assert.AreEqual(typeof(JObject), prop4.ComponentType);
+ Assert.AreEqual(false, prop4.CanResetValue(o));
+ Assert.AreEqual(false, prop4.ShouldSerializeValue(o));
+ }
+ }
+}
+#endif
\ 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 24b5d56b..cea8516a 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs
@@ -7,6 +7,9 @@ using NUnit.Framework;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using System.IO;
+#if !PocketPC && !SILVERLIGHT
+using System.Web.UI;
+#endif
namespace Newtonsoft.Json.Tests.Linq
{
@@ -556,5 +559,107 @@ Parameter name: arrayIndex")]
// "JobTitle": "Manager"
//}
}
+
+#if !PocketPC && !SILVERLIGHT
+ [Test]
+ public void PropertyChanging()
+ {
+ object changing = null;
+ object changed = null;
+ int changingCount = 0;
+ int changedCount = 0;
+
+ JObject o = new JObject();
+ o.PropertyChanging += (sender, args) =>
+ {
+ JObject s = (JObject) sender;
+ changing = (s[args.PropertyName] != null) ? ((JValue)s[args.PropertyName]).Value : null;
+ changingCount++;
+ };
+ o.PropertyChanged += (sender, args) =>
+ {
+ JObject s = (JObject)sender;
+ changed = (s[args.PropertyName] != null) ? ((JValue)s[args.PropertyName]).Value : null;
+ changedCount++;
+ };
+
+ o["StringValue"] = "value1";
+ Assert.AreEqual(null, changing);
+ Assert.AreEqual("value1", changed);
+ Assert.AreEqual("value1", (string)o["StringValue"]);
+ Assert.AreEqual(1, changingCount);
+ Assert.AreEqual(1, changedCount);
+
+ o["StringValue"] = "value1";
+ Assert.AreEqual(1, changingCount);
+ Assert.AreEqual(1, changedCount);
+
+ o["StringValue"] = "value2";
+ Assert.AreEqual("value1", changing);
+ Assert.AreEqual("value2", changed);
+ Assert.AreEqual("value2", (string)o["StringValue"]);
+ Assert.AreEqual(2, changingCount);
+ Assert.AreEqual(2, changedCount);
+
+ o["StringValue"] = null;
+ Assert.AreEqual("value2", changing);
+ Assert.AreEqual(null, changed);
+ Assert.AreEqual(null, (string)o["StringValue"]);
+ Assert.AreEqual(3, changingCount);
+ Assert.AreEqual(3, changedCount);
+
+ o["NullValue"] = null;
+ Assert.AreEqual(null, changing);
+ Assert.AreEqual(null, changed);
+ Assert.AreEqual(new JValue((object)null), o["NullValue"]);
+ Assert.AreEqual(4, changingCount);
+ Assert.AreEqual(4, changedCount);
+
+ o["NullValue"] = null;
+ Assert.AreEqual(4, changingCount);
+ Assert.AreEqual(4, changedCount);
+ }
+#endif
+
+ [Test]
+ public void PropertyChanged()
+ {
+ object changed = null;
+ int changedCount = 0;
+
+ JObject o = new JObject();
+ o.PropertyChanged += (sender, args) =>
+ {
+ JObject s = (JObject)sender;
+ changed = (s[args.PropertyName] != null) ? ((JValue)s[args.PropertyName]).Value : null;
+ changedCount++;
+ };
+
+ o["StringValue"] = "value1";
+ Assert.AreEqual("value1", changed);
+ Assert.AreEqual("value1", (string)o["StringValue"]);
+ Assert.AreEqual(1, changedCount);
+
+ o["StringValue"] = "value1";
+ Assert.AreEqual(1, changedCount);
+
+ o["StringValue"] = "value2";
+ Assert.AreEqual("value2", changed);
+ Assert.AreEqual("value2", (string)o["StringValue"]);
+ Assert.AreEqual(2, changedCount);
+
+ o["StringValue"] = null;
+ Assert.AreEqual(null, changed);
+ Assert.AreEqual(null, (string)o["StringValue"]);
+ Assert.AreEqual(3, changedCount);
+
+ o["NullValue"] = null;
+ Assert.AreEqual(null, changed);
+ Assert.AreEqual(new JValue((object)null), o["NullValue"]);
+ Assert.AreEqual(4, changedCount);
+
+ o["NullValue"] = null;
+ Assert.AreEqual(4, changedCount);
+ }
}
}
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj
index 8ee9bfa3..e70648aa 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj
@@ -61,6 +61,10 @@
+
+
+
+
@@ -69,6 +73,7 @@
+
@@ -132,7 +137,6 @@
-
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
index bfa1091a..1d9ca0e7 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
@@ -68,7 +68,12 @@
+
+
+
+
+
@@ -136,7 +141,6 @@
-
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj
index 5d92e233..9f3e67a6 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj
@@ -67,6 +67,10 @@
+
+
+
+
@@ -75,6 +79,7 @@
+
@@ -138,7 +143,6 @@
-
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 41b72e8b..82cb273e 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -105,6 +105,10 @@
+
+
+
+
@@ -173,7 +177,7 @@
-
+
diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
similarity index 90%
rename from Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs
rename to Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
index 25af25e3..5f30620f 100644
--- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
@@ -46,7 +46,7 @@ using Newtonsoft.Json.Tests.TestObjects;
using System.Runtime.Serialization;
using System.Globalization;
-namespace Newtonsoft.Json.Tests
+namespace Newtonsoft.Json.Tests.Serialization
{
public class JsonSerializerTest : TestFixtureBase
{
@@ -1291,7 +1291,7 @@ keyword such as type of business.""
}
[Test]
- [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Could not create an instance of type Newtonsoft.Json.Tests.JsonSerializerTest+ICo. Type is an interface or abstract class and cannot be instantated.")]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Could not create an instance of type Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+ICo. Type is an interface or abstract class and cannot be instantated.")]
public void DeserializeInterfaceProperty()
{
Test testClass = new Test();
@@ -2049,5 +2049,158 @@ keyword such as type of business.""
NullableDateTimeTestClass c = JsonConvert.DeserializeObject(json);
Assert.AreEqual(null, c.DateTimeField);
}
+
+ ///
+ /// What types of events are there? Just sticking to a basic set of four for now.
+ ///
+ ///
+ public enum EventType
+ {
+ Debug = 0,
+ Info = 1,
+ Warning = 2,
+ Error = 3
+ }
+
+ public sealed class Event
+ {
+
+ ///
+ /// If no current user is specified, returns Nothing (0 from VB)
+ ///
+ ///
+ ///
+ private static int GetCurrentUserId()
+ {
+ return 0;
+ }
+
+ ///
+ /// Gets either the application path or the current stack trace.
+ /// NOTE: You MUST call this from the top level entry point. Otherwise,
+ /// the stack trace will be buried in Logger itself.
+ ///
+ ///
+ ///
+ private static string GetCurrentSubLocation()
+ {
+ return "";
+ }
+
+ private string _sublocation;
+ private int _userId;
+ private EventType _type;
+ private string _summary;
+ private string _details;
+ private string _stackTrace;
+ private string _tag;
+ private DateTime _time;
+
+ public Event(string summary)
+ {
+ _summary = summary;
+ _time = DateTime.Now;
+
+ if (_userId == 0) _userId = GetCurrentUserId();
+ //This call only works at top level for now.
+ //If _stackTrace = Nothing Then _stackTrace = Environment.StackTrace
+ if (_sublocation == null) _sublocation = GetCurrentSubLocation();
+ }
+
+ public Event(string sublocation, int userId, EventType type, string summary, string details, string stackTrace, string tag)
+ {
+ _sublocation = sublocation;
+ _userId = userId;
+ _type = type;
+ _summary = summary;
+ _details = details;
+ _stackTrace = stackTrace;
+ _tag = tag;
+ _time = DateTime.Now;
+
+ if (_userId == 0) _userId = GetCurrentUserId();
+ //If _stackTrace = Nothing Then _stackTrace = Environment.StackTrace
+ if (_sublocation == null) _sublocation = GetCurrentSubLocation();
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{{ sublocation = {0}, userId = {1}, type = {2}, summary = {3}, details = {4}, stackTrace = {5}, tag = {6} }}", _sublocation, _userId, _type, _summary, _details, _stackTrace, _tag);
+ }
+
+ public string sublocation
+ {
+ get { return _sublocation; }
+ set { _sublocation = value; }
+ }
+ public int userId
+ {
+ get { return _userId; }
+ set { _userId = value; }
+ }
+ public EventType type
+ {
+ get { return _type; }
+ set { _type = value; }
+ }
+ public string summary
+ {
+ get { return _summary; }
+ set { _summary = value; }
+ }
+ public string details
+ {
+ get { return _details; }
+ set { _details = value; }
+ }
+ public string stackTrace
+ {
+ get { return _stackTrace; }
+ set { _stackTrace = value; }
+ }
+ public string tag
+ {
+ get { return _tag; }
+ set { _tag = value; }
+ }
+ public DateTime time
+ {
+ get { return _time; }
+ }
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unable to determine which constructor to use for type Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+Event. A class with no default constructor should have only one constructor with arguments.")]
+ public void FailWhenClassWithNoDefaultConstructorHasMultipleConstructorsWithArguments()
+ {
+ string json = @"{""sublocation"":""AlertEmailSender.Program.Main"",""userId"":0,""type"":0,""summary"":""Loading settings variables"",""details"":null,""stackTrace"":"" at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)\r\n at System.Environment.get_StackTrace()\r\n at mr.Logging.Event..ctor(String summary) in C:\\Projects\\MRUtils\\Logging\\Event.vb:line 71\r\n at AlertEmailSender.Program.Main(String[] args) in C:\\Projects\\AlertEmailSender\\AlertEmailSender\\Program.cs:line 25"",""tag"":null,""time"":""\/Date(1249591032026-0400)\/""}";
+
+ Event e = JsonConvert.DeserializeObject(json);
+ }
+
+ public class SetOnlyPropertyClass2
+ {
+ private object _value;
+ public object SetOnlyProperty
+ {
+ set { _value = value; }
+ }
+ public object GetValue()
+ {
+ return _value;
+ }
+ }
+
+ [Test]
+ public void DeserializeObjectSetOnlyProperty()
+ {
+ string json = @"{'SetOnlyProperty':[1,2,3,4,5]}";
+
+ SetOnlyPropertyClass2 setOnly = JsonConvert.DeserializeObject(json);
+ JArray a = (JArray)setOnly.GetValue();
+ Assert.AreEqual(5, a.Count);
+ Assert.AreEqual(1, (int)a[0]);
+ Assert.AreEqual(5, (int)a[a.Count - 1]);
+ }
}
}
\ 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 ad616391..f3e65e9f 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/PopulateTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/PopulateTests.cs
@@ -1,4 +1,29 @@
-using System;
+#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.IO;
using System.Linq;
@@ -15,8 +40,7 @@ namespace Newtonsoft.Json.Tests.Serialization
{
Person p = new Person();
- JsonSerializer serializer = new JsonSerializer();
- serializer.Populate(new StringReader(@"{""Name"":""James""}"), p);
+ JsonConvert.PopulateObject(@"{""Name"":""James""}", p);
Assert.AreEqual("James", p.Name);
}
@@ -71,9 +95,10 @@ namespace Newtonsoft.Json.Tests.Serialization
]
}";
- JsonSerializer serializer = new JsonSerializer();
- serializer.ObjectCreationHandling = ObjectCreationHandling.Replace;
- serializer.Populate(new StringReader(json), s);
+ JsonConvert.PopulateObject(json, s, new JsonSerializerSettings
+ {
+ ObjectCreationHandling = ObjectCreationHandling.Replace
+ });
Assert.AreEqual(1, s.Mottos.Count);
Assert.AreEqual("Fail whale", s.Mottos[0]);
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs
index e0b018e0..61dec3e4 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs
@@ -26,13 +26,18 @@
#if !PocketPC && !SILVERLIGHT && !NET20
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
+using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Tests;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
+using Newtonsoft.Json.Linq;
+using System.Collections;
namespace Newtonsoft.Json.Tests.Serialization
{
@@ -47,6 +52,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("Hello World!", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
+ Assert.AreEqual(null, obj.Member5);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Assert.AreEqual(@"{
@@ -59,13 +65,22 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("This value was reset after serialization.", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
+ Assert.AreEqual("Error message for member Member6 = Exception has been thrown by the target of an invocation.", obj.Member5);
- obj = JsonConvert.DeserializeObject(json);
+ JObject o = JObject.Parse(@"{
+ ""Member1"": 11,
+ ""Member2"": ""This value went into the data file during serialization."",
+ ""Member4"": null
+}");
+ o["Member6"] = "Dummy text for error";
+
+ obj = JsonConvert.DeserializeObject(o.ToString());
Assert.AreEqual(11, obj.Member1);
Assert.AreEqual("This value went into the data file during serialization.", obj.Member2);
Assert.AreEqual("This value was set during deserialization", obj.Member3);
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
+ Assert.AreEqual("Error message for member Member6 = Exception has been thrown by the target of an invocation.", obj.Member5);
}
[Test]
@@ -98,6 +113,136 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
}
+ public class ListErrorObject
+ {
+ public string Member
+ {
+ get { throw new Exception("ListErrorObject.Member get error!"); }
+ set { throw new Exception("ListErrorObject.Member set error!"); }
+ }
+ }
+
+ public class ListErrorObjectCollection : Collection
+ {
+ [OnError]
+ internal void OnErrorMethod(StreamingContext context, ErrorContext errorContext)
+ {
+ errorContext.Handled = true;
+ }
+ }
+
+ public class VersionKeyedCollection : KeyedCollection, IList
+ {
+ public List Messages { get; set; }
+
+ public VersionKeyedCollection()
+ {
+ Messages = new List();
+ }
+
+ protected override string GetKeyForItem(Person item)
+ {
+ return item.Name;
+ }
+
+ [OnError]
+ internal void OnErrorMethod(StreamingContext context, ErrorContext errorContext)
+ {
+ Messages.Add("Error message for member " + errorContext.Member + " = " + errorContext.Error.Message);
+ errorContext.Handled = true;
+ }
+
+ object IList.this[int index]
+ {
+ get
+ {
+ if (index % 2 == 0)
+ throw new Exception("Index even: " + index);
+
+ return this[index];
+ }
+ set { this[index] = (Person)value; }
+ }
+ }
+
+ [Test]
+ public void ErrorDeserializingListHandled()
+ {
+ string json = @"[
+ {
+ ""Name"": ""Jim"",
+ ""BirthDate"": ""\/Date(978048000000)\/"",
+ ""LastModified"": ""\/Date(978048000000)\/""
+ },
+ {
+ ""Name"": ""Jim"",
+ ""BirthDate"": ""\/Date(978048000000)\/"",
+ ""LastModified"": ""\/Date(978048000000)\/""
+ }
+]";
+
+ VersionKeyedCollection c = JsonConvert.DeserializeObject(json);
+ Assert.AreEqual(1, c.Count);
+ Assert.AreEqual(1, c.Messages.Count);
+ Assert.AreEqual("Error message for member 1 = An item with the same key has already been added.", c.Messages[0]);
+ }
+
+ [Test]
+ public void ErrorSerializingListHandled()
+ {
+ VersionKeyedCollection c = new VersionKeyedCollection();
+ c.Add(new Person
+ {
+ Name = "Jim",
+ BirthDate = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc),
+ LastModified = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc)
+ });
+ c.Add(new Person
+ {
+ Name = "Jimbo",
+ BirthDate = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc),
+ LastModified = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc)
+ });
+ c.Add(new Person
+ {
+ Name = "Jimmy",
+ BirthDate = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc),
+ LastModified = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc)
+ });
+ c.Add(new Person
+ {
+ Name = "Jim Bean",
+ BirthDate = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc),
+ LastModified = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc)
+ });
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ Assert.AreEqual(@"[
+ {
+ ""Name"": ""Jimbo"",
+ ""BirthDate"": ""\/Date(978048000000)\/"",
+ ""LastModified"": ""\/Date(978048000000)\/""
+ },
+ {
+ ""Name"": ""Jim Bean"",
+ ""BirthDate"": ""\/Date(978048000000)\/"",
+ ""LastModified"": ""\/Date(978048000000)\/""
+ }
+]", json);
+
+ Assert.AreEqual(2, c.Messages.Count);
+ Assert.AreEqual("Error message for member 0 = Index even: 0", c.Messages[0]);
+ Assert.AreEqual("Error message for member 2 = Index even: 2", c.Messages[1]);
+ }
+
+ [Test]
+ [ExpectedException(typeof(TargetInvocationException))]
+ public void ErrorInChild()
+ {
+ JsonConvert.DeserializeObject(@"[{""Member"":""Value""}]");
+ }
+
[Test]
public void ListEvents()
{
@@ -187,6 +332,8 @@ namespace Newtonsoft.Json.Tests.Serialization
// This is a nonserialized value
Console.WriteLine(obj.Member4);
// null
+ Console.WriteLine(obj.Member5);
+ // null
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
// {
@@ -203,6 +350,8 @@ namespace Newtonsoft.Json.Tests.Serialization
// This is a nonserialized value
Console.WriteLine(obj.Member4);
// null
+ Console.WriteLine(obj.Member5);
+ // Error message for member Member6 = Exception has been thrown by the target of an invocation.
obj = JsonConvert.DeserializeObject(json);
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestList.cs b/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestList.cs
index 0b712023..0583b735 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestList.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestList.cs
@@ -26,6 +26,7 @@
#if !PocketPC && !SILVERLIGHT
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
+using Newtonsoft.Json.Tests.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObject.cs b/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObject.cs
index 190d476d..8c9d4374 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObject.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObject.cs
@@ -23,11 +23,12 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
-#if !PocketPC && !SILVERLIGHT
+#if !PocketPC && !SILVERLIGHT && !NET20
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
+using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
@@ -48,6 +49,17 @@ namespace Newtonsoft.Json.Tests.TestObjects
// This field is set to null, but populated after deserialization.
public string Member4 { get; set; }
+ // This field is set to null, but populated after error.
+ [JsonIgnore]
+ public string Member5 { get; set; }
+
+ // Getting or setting this field will throw an error.
+ public string Member6
+ {
+ get { throw new Exception("Member5 get error!"); }
+ set { throw new Exception("Member5 set error!"); }
+ }
+
public SerializationEventTestObject()
{
Member1 = 11;
@@ -79,6 +91,13 @@ namespace Newtonsoft.Json.Tests.TestObjects
{
Member4 = "This value was set after deserialization.";
}
+
+ [OnError]
+ internal void OnErrorMethod(StreamingContext context, ErrorContext errorContext)
+ {
+ Member5 = "Error message for member " + errorContext.Member + " = " + errorContext.Error.Message;
+ errorContext.Handled = true;
+ }
}
}
#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObjectWithConstructor.cs b/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObjectWithConstructor.cs
index 943da942..6b315272 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObjectWithConstructor.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/SerializationEventTestObjectWithConstructor.cs
@@ -24,7 +24,9 @@
#endregion
#if !PocketPC && !SILVERLIGHT
+using System;
using System.Runtime.Serialization;
+using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
diff --git a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs
index 031f3101..44436639 100644
--- a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs
@@ -25,9 +25,6 @@
#if !PocketPC && !SILVERLIGHT && !NET20
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Data;
using Newtonsoft.Json.Serialization;
using System.Globalization;
@@ -53,7 +50,7 @@ namespace Newtonsoft.Json.Converters
if (keyType != null)
{
string valueJson;
- if (JsonSerializerWriter.TryConvertToString(entityKeyMember.Value, keyType, out valueJson))
+ if (JsonSerializerInternalWriter.TryConvertToString(entityKeyMember.Value, keyType, out valueJson))
writer.WriteValue(valueJson);
else
writer.WriteValue(entityKeyMember.Value);
diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs
index d62395e5..6b6eb17e 100644
--- a/Src/Newtonsoft.Json/JsonConvert.cs
+++ b/Src/Newtonsoft.Json/JsonConvert.cs
@@ -628,6 +628,26 @@ namespace Newtonsoft.Json
return deserializedValue;
}
+ public static void PopulateObject(string value, object target)
+ {
+ PopulateObject(value, target, null);
+ }
+
+
+ public static void PopulateObject(string value, object target, JsonSerializerSettings settings)
+ {
+ StringReader sr = new StringReader(value);
+ JsonSerializer jsonSerializer = JsonSerializer.Create(settings);
+
+ using (JsonReader jsonReader = new JsonTextReader(sr))
+ {
+ jsonSerializer.Populate(jsonReader, target);
+
+ if (jsonReader.Read() && jsonReader.TokenType != JsonToken.Comment)
+ throw new JsonSerializationException("Additional text found in JSON string after finishing deserializing object.");
+ }
+ }
+
#if !SILVERLIGHT
///
/// Serializes the XML node to a JSON string.
diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs
index 76309c9c..9084247d 100644
--- a/Src/Newtonsoft.Json/JsonSerializer.cs
+++ b/Src/Newtonsoft.Json/JsonSerializer.cs
@@ -309,7 +309,7 @@ namespace Newtonsoft.Json
ValidationUtils.ArgumentNotNull(reader, "reader");
ValidationUtils.ArgumentNotNull(target, "target");
- JsonSerializerReader serializerReader = new JsonSerializerReader(this);
+ JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
serializerReader.Populate(reader, target);
}
@@ -351,7 +351,7 @@ namespace Newtonsoft.Json
{
ValidationUtils.ArgumentNotNull(reader, "reader");
- JsonSerializerReader serializerReader = new JsonSerializerReader(this);
+ JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
return serializerReader.Deserialize(reader, objectType);
}
@@ -381,7 +381,7 @@ namespace Newtonsoft.Json
{
ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
- JsonSerializerWriter serializerWriter = new JsonSerializerWriter(this);
+ JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(this);
serializerWriter.Serialize(jsonWriter, value);
}
diff --git a/Src/Newtonsoft.Json/Linq/ComponentModel/JPropertyDescriptor.cs b/Src/Newtonsoft.Json/Linq/ComponentModel/JPropertyDescriptor.cs
new file mode 100644
index 00000000..81edf638
--- /dev/null
+++ b/Src/Newtonsoft.Json/Linq/ComponentModel/JPropertyDescriptor.cs
@@ -0,0 +1,158 @@
+#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
+
+#if !SILVERLIGHT
+using System;
+using System.ComponentModel;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Linq.ComponentModel
+{
+ ///
+ /// Represents a view of a .
+ ///
+ public class JPropertyDescriptor : PropertyDescriptor
+ {
+ private readonly Type _propertyType;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name.
+ /// Type of the property.
+ public JPropertyDescriptor(string name, Type propertyType)
+ : base(name, null)
+ {
+ ValidationUtils.ArgumentNotNull(name, "name");
+ ValidationUtils.ArgumentNotNull(propertyType, "propertyType");
+
+ _propertyType = propertyType;
+ }
+
+ private static JObject CastInstance(object instance)
+ {
+ return (JObject)instance;
+ }
+
+ ///
+ /// When overridden in a derived class, returns whether resetting an object changes its value.
+ ///
+ ///
+ /// true if resetting the component changes its value; otherwise, false.
+ ///
+ /// The component to test for reset capability.
+ ///
+ public override bool CanResetValue(object component)
+ {
+ return false;
+ }
+
+ ///
+ /// When overridden in a derived class, gets the current value of the property on a component.
+ ///
+ ///
+ /// The value of a property for a given component.
+ ///
+ /// The component with the property for which to retrieve the value.
+ ///
+ public override object GetValue(object component)
+ {
+ JToken token = CastInstance(component)[Name];
+ if (token is JValue)
+ return ((JValue) token).Value;
+
+ return token;
+ }
+
+ ///
+ /// When overridden in a derived class, resets the value for this property of the component to the default value.
+ ///
+ /// The component with the property value that is to be reset to the default value.
+ ///
+ public override void ResetValue(object component)
+ {
+ }
+
+ ///
+ /// When overridden in a derived class, sets the value of the component to a different value.
+ ///
+ /// The component with the property value that is to be set.
+ /// The new value.
+ ///
+ public override void SetValue(object component, object value)
+ {
+ JToken token = (value is JToken) ? (JToken) value : new JValue(value);
+
+ CastInstance(component)[Name] = token;
+ }
+
+ ///
+ /// When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted.
+ ///
+ ///
+ /// true if the property should be persisted; otherwise, false.
+ ///
+ /// The component with the property to be examined for persistence.
+ ///
+ public override bool ShouldSerializeValue(object component)
+ {
+ return false;
+ }
+
+ ///
+ /// When overridden in a derived class, gets the type of the component this property is bound to.
+ ///
+ ///
+ /// A that represents the type of component this property is bound to. When the or methods are invoked, the object specified might be an instance of this type.
+ ///
+ public override Type ComponentType
+ {
+ get { return typeof(JObject); }
+ }
+
+ ///
+ /// When overridden in a derived class, gets a value indicating whether this property is read-only.
+ ///
+ ///
+ /// true if the property is read-only; otherwise, false.
+ ///
+ public override bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ ///
+ /// When overridden in a derived class, gets the type of the property.
+ ///
+ ///
+ /// A that represents the type of the property.
+ ///
+ public override Type PropertyType
+ {
+ get { return _propertyType; }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Linq/ComponentModel/JTypeDescriptionProvider.cs b/Src/Newtonsoft.Json/Linq/ComponentModel/JTypeDescriptionProvider.cs
new file mode 100644
index 00000000..c5f5fc12
--- /dev/null
+++ b/Src/Newtonsoft.Json/Linq/ComponentModel/JTypeDescriptionProvider.cs
@@ -0,0 +1,47 @@
+#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
+
+#if !PocketPC && !SILVERLIGHT
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Linq.ComponentModel
+{
+ internal class JTypeDescriptionProvider : TypeDescriptionProvider
+ {
+ public override ICustomTypeDescriptor GetTypeDescriptor(Type type, object instance)
+ {
+ JObject o = instance as JObject;
+ if (o != null)
+ return new JTypeDescriptor(o);
+
+ return base.GetTypeDescriptor(type, instance);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Linq/ComponentModel/JTypeDescriptor.cs b/Src/Newtonsoft.Json/Linq/ComponentModel/JTypeDescriptor.cs
new file mode 100644
index 00000000..604e9b95
--- /dev/null
+++ b/Src/Newtonsoft.Json/Linq/ComponentModel/JTypeDescriptor.cs
@@ -0,0 +1,209 @@
+#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
+
+#if !SILVERLIGHT
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Linq.ComponentModel
+{
+ ///
+ /// Represents a view of a .
+ ///
+ public class JTypeDescriptor : ICustomTypeDescriptor
+ {
+ private readonly JObject _value;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ public JTypeDescriptor(JObject value)
+ {
+ ValidationUtils.ArgumentNotNull(value, "value");
+ _value = value;
+ }
+
+ ///
+ /// Returns the properties for this instance of a component.
+ ///
+ ///
+ /// A that represents the properties for this component instance.
+ ///
+ public virtual PropertyDescriptorCollection GetProperties()
+ {
+ return GetProperties(null);
+ }
+
+ private static Type GetTokenPropertyType(JToken token)
+ {
+ if (token is JValue)
+ {
+ JValue v = (JValue) token;
+ return (v.Value != null) ? v.Value.GetType() : typeof (object);
+ }
+
+ return token.GetType();
+ }
+
+ ///
+ /// Returns the properties for this instance of a component using the attribute array as a filter.
+ ///
+ /// An array of type that is used as a filter.
+ ///
+ /// A that represents the filtered properties for this component instance.
+ ///
+ public virtual PropertyDescriptorCollection GetProperties(Attribute[] attributes)
+ {
+ PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null);
+
+ if (_value != null)
+ {
+ foreach (KeyValuePair propertyValue in _value)
+ {
+ descriptors.Add(new JPropertyDescriptor(propertyValue.Key, GetTokenPropertyType(propertyValue.Value)));
+ }
+ }
+
+ return descriptors;
+ }
+
+ ///
+ /// Returns a collection of custom attributes for this instance of a component.
+ ///
+ ///
+ /// An containing the attributes for this object.
+ ///
+ public AttributeCollection GetAttributes()
+ {
+ return AttributeCollection.Empty;
+ }
+
+ ///
+ /// Returns the class name of this instance of a component.
+ ///
+ ///
+ /// The class name of the object, or null if the class does not have a name.
+ ///
+ public string GetClassName()
+ {
+ return null;
+ }
+
+ ///
+ /// Returns the name of this instance of a component.
+ ///
+ ///
+ /// The name of the object, or null if the object does not have a name.
+ ///
+ public string GetComponentName()
+ {
+ return null;
+ }
+
+ ///
+ /// Returns a type converter for this instance of a component.
+ ///
+ ///
+ /// A that is the converter for this object, or null if there is no for this object.
+ ///
+ public TypeConverter GetConverter()
+ {
+ return new TypeConverter();
+ }
+
+ ///
+ /// Returns the default event for this instance of a component.
+ ///
+ ///
+ /// An that represents the default event for this object, or null if this object does not have events.
+ ///
+ public EventDescriptor GetDefaultEvent()
+ {
+ return null;
+ }
+
+ ///
+ /// Returns the default property for this instance of a component.
+ ///
+ ///
+ /// A that represents the default property for this object, or null if this object does not have properties.
+ ///
+ public PropertyDescriptor GetDefaultProperty()
+ {
+ return null;
+ }
+
+ ///
+ /// Returns an editor of the specified type for this instance of a component.
+ ///
+ /// A that represents the editor for this object.
+ ///
+ /// An of the specified type that is the editor for this object, or null if the editor cannot be found.
+ ///
+ public object GetEditor(Type editorBaseType)
+ {
+ return null;
+ }
+
+ ///
+ /// Returns the events for this instance of a component using the specified attribute array as a filter.
+ ///
+ /// An array of type that is used as a filter.
+ ///
+ /// An that represents the filtered events for this component instance.
+ ///
+ public EventDescriptorCollection GetEvents(Attribute[] attributes)
+ {
+ return EventDescriptorCollection.Empty;
+ }
+
+ ///
+ /// Returns the events for this instance of a component.
+ ///
+ ///
+ /// An that represents the events for this component instance.
+ ///
+ public EventDescriptorCollection GetEvents()
+ {
+ return EventDescriptorCollection.Empty;
+ }
+
+ ///
+ /// Returns an object that contains the property described by the specified property descriptor.
+ ///
+ /// A that represents the property whose owner is to be found.
+ ///
+ /// An that represents the owner of the specified property.
+ ///
+ public object GetPropertyOwner(PropertyDescriptor pd)
+ {
+ return null;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs
index d9cdcaa3..8a1106f0 100644
--- a/Src/Newtonsoft.Json/Linq/JContainer.cs
+++ b/Src/Newtonsoft.Json/Linq/JContainer.cs
@@ -204,7 +204,7 @@ namespace Newtonsoft.Json.Linq
{
if (IsMultiContent(content))
{
- IEnumerable enumerable = content as IEnumerable;
+ IEnumerable enumerable = (IEnumerable)content;
JToken multiPrevious = previous;
foreach (object c in enumerable)
diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs
index db0042d7..2aebaefe 100644
--- a/Src/Newtonsoft.Json/Linq/JObject.cs
+++ b/Src/Newtonsoft.Json/Linq/JObject.cs
@@ -25,19 +25,39 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
-using System.Text;
using System.IO;
using Newtonsoft.Json.Utilities;
using System.Globalization;
+#if !PocketPC && !SILVERLIGHT
+using Newtonsoft.Json.Linq.ComponentModel;
+#endif
namespace Newtonsoft.Json.Linq
{
///
/// Represents a JSON object.
///
- public class JObject : JContainer, IDictionary
+#if !PocketPC && !SILVERLIGHT
+ [TypeDescriptionProvider(typeof(JTypeDescriptionProvider))]
+#endif
+ public class JObject : JContainer, IDictionary, INotifyPropertyChanged
+#if !PocketPC && !SILVERLIGHT
+ , INotifyPropertyChanging
+#endif
{
+ ///
+ /// Occurs when a property value changes.
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+#if !PocketPC && !SILVERLIGHT
+ ///
+ /// Occurs when a property value is changing.
+ ///
+ public event PropertyChangingEventHandler PropertyChanging;
+#endif
+
///
/// Initializes a new instance of the class.
///
@@ -171,12 +191,42 @@ namespace Newtonsoft.Json.Linq
{
JProperty property = Property(propertyName);
if (property != null)
- property.Value = value;
+ {
+ if (!IsTokenUnchanged(property.Value, value))
+ {
+#if !PocketPC && !SILVERLIGHT
+ OnPropertyChanging(property.Name);
+#endif
+ property.Value = value;
+ OnPropertyChanged(property.Name);
+ }
+ }
else
+ {
+#if !PocketPC && !SILVERLIGHT
+ OnPropertyChanging(propertyName);
+#endif
Add(new JProperty(propertyName, value));
+ OnPropertyChanged(propertyName);
+ }
}
}
+ private static bool IsTokenUnchanged(JToken currentValue, JToken newValue)
+ {
+ JValue v1 = currentValue as JValue;
+ if (v1 != null)
+ {
+ // null will get turned into a JValue of type null
+ if (v1.Type == JTokenType.Null && newValue == null)
+ return true;
+
+ return v1.Equals(newValue);
+ }
+
+ return false;
+ }
+
///
/// Loads an from a .
///
@@ -219,7 +269,6 @@ namespace Newtonsoft.Json.Linq
return Load(jsonReader);
}
-
///
/// Creates a from an object.
///
@@ -246,7 +295,6 @@ namespace Newtonsoft.Json.Linq
return (JObject)token;
}
-
internal override void ValidateObject(JToken o, JToken previous)
{
ValidationUtils.ArgumentNotNull(o, "o");
@@ -418,5 +466,19 @@ namespace Newtonsoft.Json.Linq
yield return new KeyValuePair(property.Name, property.Value);
}
}
+
+ protected virtual void OnPropertyChanged(string propertyName)
+ {
+ if (PropertyChanged != null)
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+#if !PocketPC && !SILVERLIGHT
+ protected virtual void OnPropertyChanging(string propertyName)
+ {
+ if (PropertyChanging != null)
+ PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
+ }
+#endif
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs
index 01d435e5..97c88667 100644
--- a/Src/Newtonsoft.Json/Linq/JValue.cs
+++ b/Src/Newtonsoft.Json/Linq/JValue.cs
@@ -35,7 +35,7 @@ namespace Newtonsoft.Json.Linq
///
/// Represents a value in JSON (string, integer, date, etc).
///
- public class JValue : JToken
+ public class JValue : JToken, IEquatable
{
private JTokenType _valueType;
private object _value;
@@ -327,5 +327,50 @@ namespace Newtonsoft.Json.Linq
return _valueType.GetHashCode() ^ valueHashCode;
}
+
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ /// An object to compare with this object.
+ public bool Equals(JValue other)
+ {
+ if (other == null)
+ return false;
+
+ return (_value == other._value);
+ }
+
+ ///
+ /// 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)
+ {
+ if (obj == null)
+ return false;
+
+ JValue otherValue = obj as JValue;
+ if (otherValue != null)
+ return Equals(otherValue);
+
+ return base.Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ if (_value == null)
+ return 0;
+
+ return _value.GetHashCode();
+ }
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
index c44903bf..d9a7a5a7 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
@@ -70,6 +70,9 @@
+
+
+
@@ -121,6 +124,7 @@
+
@@ -138,10 +142,12 @@
+
+
+
-
-
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
index e8306d94..9c118e63 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
@@ -81,6 +81,9 @@
+
+
+
@@ -139,6 +142,7 @@
+
@@ -155,11 +159,13 @@
+
+
+
-
-
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
index 4cf3632b..1069caf5 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
@@ -82,6 +82,9 @@
+
+
+
@@ -117,9 +120,10 @@
+
-
-
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index 9e7613e9..78f2b6e3 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -90,6 +90,9 @@
+
+
+
@@ -148,6 +151,7 @@
+
@@ -164,11 +168,13 @@
+
+
+
-
-
+
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
index 482ea5bf..96b9f689 100644
--- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
@@ -183,6 +183,10 @@ namespace Newtonsoft.Json.Serialization
{
contract.OnDeserialized = method;
}
+ if (IsValidCallback(method, parameters, typeof(OnErrorAttribute), contract.OnError, ref prevAttributeType))
+ {
+ contract.OnError = method;
+ }
}
#endif
}
@@ -249,8 +253,16 @@ namespace Newtonsoft.Json.Serialization
if (method.ReturnType != typeof(void))
throw new Exception("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method));
- if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))
- throw new Exception("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext)));
+ if (attributeType == typeof(OnErrorAttribute))
+ {
+ if (parameters == null || parameters.Length != 2 || parameters[0].ParameterType != typeof(StreamingContext) || parameters[1].ParameterType != typeof(ErrorContext))
+ throw new Exception("Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof (StreamingContext), typeof(ErrorContext)));
+ }
+ else
+ {
+ if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))
+ throw new Exception("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext)));
+ }
prevAttributeType = attributeType;
diff --git a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs
new file mode 100644
index 00000000..1dff26df
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs
@@ -0,0 +1,68 @@
+#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
+
+#if !PocketPC && !SILVERLIGHT && !NET20
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Serialization
+{
+ ///
+ /// Provides information surrounding an error.
+ ///
+ public class ErrorContext
+ {
+ internal ErrorContext(object originalObject, object member, Exception error)
+ {
+ OriginalObject = originalObject;
+ Member = member;
+ Error = error;
+ }
+
+ ///
+ /// Gets or sets the error.
+ ///
+ /// The error.
+ public Exception Error { get; private set; }
+ ///
+ /// Gets the original object that caused the error.
+ ///
+ /// The original object that caused the error.
+ public object OriginalObject { get; private set; }
+ ///
+ /// Gets the member that caused the error.
+ ///
+ /// The member that caused the error.
+ public object Member { get; private set; }
+ ///
+ /// Gets or sets a value indicating whether this is handled.
+ ///
+ /// true if handled; otherwise, false.
+ public bool Handled { get; set; }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs
index 6655fe24..f02984df 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs
@@ -47,7 +47,8 @@ namespace Newtonsoft.Json.Serialization
public bool? IsReference { get; set; }
#if !PocketPC && !SILVERLIGHT
- private static readonly object[] SerializationEventParameterValues = new object[] { new StreamingContext(StreamingContextStates.All) };
+ private static readonly StreamingContext SerializationStreamingContextParameter = new StreamingContext(StreamingContextStates.All);
+ private static readonly object[] SerializationEventParameterValues = new object[] { SerializationStreamingContextParameter };
///
/// Gets or sets the method called immediately after deserialization of the object.
@@ -69,6 +70,8 @@ namespace Newtonsoft.Json.Serialization
///
/// The method called before serialization of the object.
public MethodInfo OnSerializing { get; set; }
+
+ public MethodInfo OnError { get; set; }
#endif
internal void InvokeOnSerializing(object o)
@@ -103,6 +106,14 @@ namespace Newtonsoft.Json.Serialization
#endif
}
+#if !PocketPC && !SILVERLIGHT && !NET20
+ internal void InvokeOnError(object o, ErrorContext errorContext)
+ {
+ if (OnError != null && o == errorContext.OriginalObject)
+ OnError.Invoke(o, new object[] { SerializationStreamingContextParameter, errorContext });
+ }
+#endif
+
internal JsonContract(Type underlyingType)
{
ValidationUtils.ArgumentNotNull(underlyingType, "underlyingType");
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs
new file mode 100644
index 00000000..c3cd4feb
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs
@@ -0,0 +1,57 @@
+#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.Net;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Serialization
+{
+ internal abstract class JsonSerializerInternalBase
+ {
+#if !PocketPC && !SILVERLIGHT && !NET20
+ private ErrorContext _currentErrorContext;
+
+ protected ErrorContext GetErrorContext(object originalObject, object member, Exception error)
+ {
+ if (_currentErrorContext == null)
+ _currentErrorContext = new ErrorContext(originalObject, member, error);
+
+ if (_currentErrorContext.Error != error)
+ throw new InvalidOperationException("Current error context error is different to requested error.");
+
+ return _currentErrorContext;
+ }
+
+ protected void ClearErrorContext()
+ {
+ if (_currentErrorContext == null)
+ throw new InvalidOperationException("Could not clear error context. Error context is already null.");
+
+ _currentErrorContext = null;
+ }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
similarity index 86%
rename from Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs
rename to Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
index c55cb05a..a665c0fb 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
@@ -35,12 +35,12 @@ using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization
{
- internal class JsonSerializerReader
+ internal class JsonSerializerInternalReader : JsonSerializerInternalBase
{
internal readonly JsonSerializer _serializer;
private JsonSerializerProxy _internalSerializer;
- public JsonSerializerReader(JsonSerializer serializer)
+ public JsonSerializerInternalReader(JsonSerializer serializer)
{
ValidationUtils.ArgumentNotNull(serializer, "serializer");
@@ -79,7 +79,7 @@ namespace Newtonsoft.Json.Serialization
else if (contract is JsonObjectContract)
PopulateObject(target, reader, (JsonObjectContract) contract, id);
else
- throw new Exception("dfsdfsdf");
+ throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
}
}
@@ -292,17 +292,16 @@ namespace Newtonsoft.Json.Serialization
return PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader, (JsonDictionaryContract) contract, id);
}
- else if (contract is JsonObjectContract)
+
+ if (contract is JsonObjectContract)
{
if (existingValue == null)
return CreateAndPopulateObject(reader, (JsonObjectContract) contract, id);
return PopulateObject(existingValue, reader, (JsonObjectContract) contract, id);
}
- else
- {
- throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
- }
+
+ throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
}
private JsonArrayContract GetArrayContract(Type objectType)
@@ -400,7 +399,8 @@ namespace Newtonsoft.Json.Serialization
bool useExistingValue = false;
if ((_serializer.ObjectCreationHandling == ObjectCreationHandling.Auto || _serializer.ObjectCreationHandling == ObjectCreationHandling.Reuse)
- && (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
+ && (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
+ && property.Readable)
{
currentValue = ReflectionUtils.GetMemberValue(property.Member, target);
@@ -457,7 +457,22 @@ namespace Newtonsoft.Json.Serialization
object keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
CheckedRead(reader);
- dictionary.Add(keyValue, CreateValue(reader, contract.DictionaryValueType, null, null));
+ try
+ {
+ dictionary.Add(keyValue, CreateValue(reader, contract.DictionaryValueType, null, null));
+ }
+ catch (Exception ex)
+ {
+#if !PocketPC && !SILVERLIGHT && !NET20
+ ErrorContext errorContext = GetErrorContext(dictionary.UnderlyingDictionary, keyValue, ex);
+ contract.InvokeOnError(dictionary.UnderlyingDictionary, errorContext);
+
+ if (errorContext.Handled)
+ ClearErrorContext();
+ else
+#endif
+ throw;
+ }
break;
case JsonToken.EndObject:
contract.InvokeOnDeserialized(dictionary.UnderlyingDictionary);
@@ -481,6 +496,8 @@ namespace Newtonsoft.Json.Serialization
#if !PocketPC && !SILVERLIGHT
if (contract.OnSerializing != null && isTemporaryListReference)
throw new JsonSerializationException("Cannot call OnSerializing on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
+ if (contract.OnError != null && isTemporaryListReference)
+ throw new JsonSerializationException("Cannot call OnError on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#endif
PopulateList(l, reader, reference, contract);
@@ -505,9 +522,24 @@ namespace Newtonsoft.Json.Serialization
case JsonToken.Comment:
break;
default:
- object value = CreateValue(reader, contract.CollectionItemType, null, null);
+ try
+ {
+ object value = CreateValue(reader, contract.CollectionItemType, null, null);
- list.Add(value);
+ list.Add(value);
+ }
+ catch (Exception ex)
+ {
+#if !PocketPC && !SILVERLIGHT && !NET20
+ ErrorContext errorContext = GetErrorContext(list, list.Count, ex);
+ contract.InvokeOnError(list, errorContext);
+
+ if (errorContext.Handled)
+ ClearErrorContext();
+ else
+#endif
+ throw;
+ }
break;
}
}
@@ -537,11 +569,15 @@ namespace Newtonsoft.Json.Serialization
{
Type objectType = contract.UnderlyingType;
- // object should have a single constructor
- ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
+ ConstructorInfo[] constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
- if (c == null)
+ if (constructors.Length == 0)
throw new JsonSerializationException("Could not find a public constructor for type {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+ if (constructors.Length > 1)
+ throw new JsonSerializationException("Unable to determine which constructor to use for type {0}. A class with no default constructor should have only one constructor with arguments.".FormatWith(CultureInfo.InvariantCulture, objectType));
+
+ // object should have a single constructor
+ ConstructorInfo c = constructors[0];
// create a dictionary to put retrieved values into
IDictionary propertyValues = contract.Properties.Where(p => !p.Ignored).ToDictionary(kv => kv, kv => (object)null);
@@ -631,8 +667,23 @@ namespace Newtonsoft.Json.Serialization
if (reader.TokenType != JsonToken.Null)
SetRequiredProperty(memberName, requiredProperties);
-
- SetObjectMember(reader, newObject, contract, memberName);
+
+ try
+ {
+ SetObjectMember(reader, newObject, contract, memberName);
+ }
+ catch (Exception ex)
+ {
+#if !PocketPC && !SILVERLIGHT && !NET20
+ ErrorContext errorContext = GetErrorContext(newObject, memberName, ex);
+ contract.InvokeOnError(newObject, errorContext);
+
+ if (errorContext.Handled)
+ ClearErrorContext();
+ else
+#endif
+ throw;
+ }
break;
case JsonToken.EndObject:
foreach (KeyValuePair requiredProperty in requiredProperties)
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
similarity index 83%
rename from Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs
rename to Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
index 27e6498e..34e9d330 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
@@ -36,12 +36,12 @@ using System.Runtime.Serialization;
namespace Newtonsoft.Json.Serialization
{
- internal class JsonSerializerWriter
+ internal class JsonSerializerInternalWriter : JsonSerializerInternalBase
{
internal readonly JsonSerializer _serializer;
private JsonSerializerProxy _internalSerializer;
private List