Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorJamesNK <james@newtonking.com>2009-05-13 14:15:41 +0400
committerJamesNK <james@newtonking.com>2009-05-13 14:15:41 +0400
commitf0c5be266b8afece71fa6463636dbedcee01a4f0 (patch)
treec9007e669fae4c0c656f3158219e45ea261c24d3 /Src
parent3b26adfdd121e8861ae8a49f85014a3027b36cbb (diff)
-Added JsonSerializer argument to JsonConverter.ReadJson and JsonConverter.WriteJson. Needed because serializer now has state
-Added CustomCreationConverter -Added IsReference to JsonContainerAttribute -Added PreserveReferencesHandling to JsonSerializer -Added IReferenceResolver to JsonSerializer -Split internals of JsonSerializer into JsonSerializerWriter (serializes) and JsonSerializerReader (deserializes) -Moved serialize stack from JsonWriter (yuck) to JsonSerializerWriter (yay) -Added FromObject overload with JsonSerializer argument for cases when state is needed
Diffstat (limited to 'Src')
-rw-r--r--Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs738
-rw-r--r--Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs4
-rw-r--r--Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs4
-rw-r--r--Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj1
-rw-r--r--Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj1
-rw-r--r--Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj1
-rw-r--r--Src/Newtonsoft.Json.Tests/TestFixtureBase.cs7
-rw-r--r--Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs4
-rw-r--r--Src/Newtonsoft.Json.Tests/TestObjects/Employee.cs39
-rw-r--r--Src/Newtonsoft.Json/Converters/BinaryConverter.cs31
-rw-r--r--Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs57
-rw-r--r--Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs4
-rw-r--r--Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs6
-rw-r--r--Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs4
-rw-r--r--Src/Newtonsoft.Json/Converters/StringEnumConverter.cs31
-rw-r--r--Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs4
-rw-r--r--Src/Newtonsoft.Json/JsonContainerAttribute.cs10
-rw-r--r--Src/Newtonsoft.Json/JsonConverter.cs6
-rw-r--r--Src/Newtonsoft.Json/JsonSerializer.cs750
-rw-r--r--Src/Newtonsoft.Json/JsonSerializerSettings.cs3
-rw-r--r--Src/Newtonsoft.Json/JsonWriter.cs14
-rw-r--r--Src/Newtonsoft.Json/Linq/JArray.cs8
-rw-r--r--Src/Newtonsoft.Json/Linq/JObject.cs11
-rw-r--r--Src/Newtonsoft.Json/Linq/JToken.cs12
-rw-r--r--Src/Newtonsoft.Json/Linq/JValue.cs2
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj10
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj10
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.csproj12
-rw-r--r--Src/Newtonsoft.Json/PreserveReferencesHandling.cs40
-rw-r--r--Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs27
-rw-r--r--Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs10
-rw-r--r--Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs82
-rw-r--r--Src/Newtonsoft.Json/Serialization/IReferenceResolver.cs35
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonMemberMapping.cs13
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs130
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs615
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs375
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs3
-rw-r--r--Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs58
-rw-r--r--Src/Newtonsoft.Json/Utilities/CollectionUtils.cs4
-rw-r--r--Src/Newtonsoft.Json/Utilities/StringBuffer.cs (renamed from Src/Newtonsoft.Json/StringBuffer.cs)2
41 files changed, 2464 insertions, 714 deletions
diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs
index 61d226f..0a3ea69 100644
--- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs
@@ -762,11 +762,12 @@ keyword such as type of business.""
[Test]
public void SerializeArrayAsArrayList()
{
- string jsonText = @"[3, ""somestring"",[1,2,3]]";
+ string jsonText = @"[3, ""somestring"",[1,2,3],{}]";
ArrayList o = JsonConvert.DeserializeObject<ArrayList>(jsonText);
- Assert.AreEqual(3, o.Count);
+ Assert.AreEqual(4, o.Count);
Assert.AreEqual(3, ((JArray)o[2]).Count);
+ Assert.AreEqual(0, ((JObject)o[3]).Count);
}
#endif
@@ -1617,5 +1618,738 @@ keyword such as type of business.""
Assert.AreEqual("_name: Jeff, _age: 26, Rank: 10, JsonTitle: Dr", cc.ToString());
}
#endif
+
+ [Test]
+ public void PopulatePerson()
+ {
+ Person p = new Person();
+
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.Populate(new StringReader(@"{""Name"":""James""}"), p);
+
+ Assert.AreEqual("James", p.Name);
+ }
+
+ [Test]
+ public void PopulateListOfPeople()
+ {
+ List<Person> p = new List<Person>();
+
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.Populate(new StringReader(@"[{""Name"":""James""},{""Name"":""Jim""}]"), p);
+
+ Assert.AreEqual(2, p.Count);
+ Assert.AreEqual("James", p[0].Name);
+ Assert.AreEqual("Jim", p[1].Name);
+ }
+
+ [Test]
+ public void PopulateDictionary()
+ {
+ Dictionary<string, string> p = new Dictionary<string, string>();
+
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.Populate(new StringReader(@"{""Name"":""James""}"), p);
+
+ Assert.AreEqual(1, p.Count);
+ Assert.AreEqual("James", p["Name"]);
+ }
+
+ [Test]
+ public void SerializeEmployeeReference()
+ {
+ Employee mikeManager = new Employee
+ {
+ Name = "Mike Manager"
+ };
+ Employee joeUser = new Employee
+ {
+ Name = "Joe User",
+ Manager = mikeManager
+ };
+
+ List<Employee> employees = new List<Employee>
+ {
+ mikeManager,
+ joeUser
+ };
+
+ string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
+ Assert.AreEqual(@"[
+ {
+ ""$id"": ""1"",
+ ""Name"": ""Mike Manager"",
+ ""Manager"": null
+ },
+ {
+ ""$id"": ""2"",
+ ""Name"": ""Joe User"",
+ ""Manager"": {
+ ""$ref"": ""1""
+ }
+ }
+]", json);
+ }
+
+ [Test]
+ public void DeserializeEmployeeReference()
+ {
+ string json = @"[
+ {
+ ""$id"": ""1"",
+ ""Name"": ""Mike Manager"",
+ ""Manager"": null
+ },
+ {
+ ""$id"": ""2"",
+ ""Name"": ""Joe User"",
+ ""Manager"": {
+ ""$ref"": ""1""
+ }
+ }
+]";
+
+ List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(json);
+
+ Assert.AreEqual(2, employees.Count);
+ Assert.AreEqual("Mike Manager", employees[0].Name);
+ Assert.AreEqual("Joe User", employees[1].Name);
+ Assert.AreEqual(employees[0], employees[1].Manager);
+ }
+
+ [Test]
+ public void SerializeCircularReference()
+ {
+ CircularReferenceClass c1 = new CircularReferenceClass {Name = "c1"};
+ CircularReferenceClass c2 = new CircularReferenceClass {Name = "c2"};
+ CircularReferenceClass c3 = new CircularReferenceClass {Name = "c3"};
+
+ c1.Child = c2;
+ c2.Child = c3;
+ c3.Child = c1;
+
+ string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
+ {
+ PreserveReferencesHandling = PreserveReferencesHandling.Objects
+ });
+
+ Assert.AreEqual(@"{
+ ""$id"": ""1"",
+ ""Name"": ""c1"",
+ ""Child"": {
+ ""$id"": ""2"",
+ ""Name"": ""c2"",
+ ""Child"": {
+ ""$id"": ""3"",
+ ""Name"": ""c3"",
+ ""Child"": {
+ ""$ref"": ""1""
+ }
+ }
+ }
+}", json);
+ }
+
+ [Test]
+ public void DeserializeCircularReference()
+ {
+ string json = @"{
+ ""$id"": ""1"",
+ ""Name"": ""c1"",
+ ""Child"": {
+ ""$id"": ""2"",
+ ""Name"": ""c2"",
+ ""Child"": {
+ ""$id"": ""3"",
+ ""Name"": ""c3"",
+ ""Child"": {
+ ""$ref"": ""1""
+ }
+ }
+ }
+}";
+
+ CircularReferenceClass c1 =
+ JsonConvert.DeserializeObject<CircularReferenceClass>(json, new JsonSerializerSettings
+ {
+ PreserveReferencesHandling = PreserveReferencesHandling.Objects
+ });
+
+ Assert.AreEqual("c1", c1.Name);
+ Assert.AreEqual("c2", c1.Child.Name);
+ Assert.AreEqual("c3", c1.Child.Child.Name);
+ Assert.AreEqual("c1", c1.Child.Child.Child.Name);
+ }
+
+ [Test]
+ public void SerializeReferenceInList()
+ {
+ Employee e1 = new Employee { Name = "e1" };
+ Employee e2 = new Employee { Name = "e2" };
+
+ List<Employee> employees = new List<Employee> { e1, e2, e1, e2 };
+
+ string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
+
+ Assert.AreEqual(@"[
+ {
+ ""$id"": ""1"",
+ ""Name"": ""e1"",
+ ""Manager"": null
+ },
+ {
+ ""$id"": ""2"",
+ ""Name"": ""e2"",
+ ""Manager"": null
+ },
+ {
+ ""$ref"": ""1""
+ },
+ {
+ ""$ref"": ""2""
+ }
+]", json);
+ }
+
+ [Test]
+ public void DeserializeReferenceInList()
+ {
+ string json = @"[
+ {
+ ""$id"": ""1"",
+ ""Name"": ""e1"",
+ ""Manager"": null
+ },
+ {
+ ""$id"": ""2"",
+ ""Name"": ""e2"",
+ ""Manager"": null
+ },
+ {
+ ""$ref"": ""1""
+ },
+ {
+ ""$ref"": ""2""
+ }
+]";
+
+ List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(json);
+ Assert.AreEqual(4, employees.Count);
+
+ Assert.AreEqual("e1", employees[0].Name);
+ Assert.AreEqual("e2", employees[1].Name);
+ Assert.AreEqual("e1", employees[2].Name);
+ Assert.AreEqual("e2", employees[3].Name);
+
+ Assert.AreEqual(employees[0], employees[2]);
+ Assert.AreEqual(employees[1], employees[3]);
+ }
+
+ [Test]
+ public void SerializeReferenceInDictionary()
+ {
+ Employee e1 = new Employee {Name = "e1"};
+ Employee e2 = new Employee {Name = "e2"};
+
+ Dictionary<string, Employee> employees = new Dictionary<string, Employee>
+ {
+ {"One", e1},
+ {"Two", e2},
+ {"Three", e1},
+ {"Four", e2}
+ };
+
+ string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
+
+ Assert.AreEqual(@"{
+ ""One"": {
+ ""$id"": ""1"",
+ ""Name"": ""e1"",
+ ""Manager"": null
+ },
+ ""Two"": {
+ ""$id"": ""2"",
+ ""Name"": ""e2"",
+ ""Manager"": null
+ },
+ ""Three"": {
+ ""$ref"": ""1""
+ },
+ ""Four"": {
+ ""$ref"": ""2""
+ }
+}", json);
+ }
+
+ [Test]
+ public void DeserializeReferenceInDictionary()
+ {
+ string json = @"{
+ ""One"": {
+ ""$id"": ""1"",
+ ""Name"": ""e1"",
+ ""Manager"": null
+ },
+ ""Two"": {
+ ""$id"": ""2"",
+ ""Name"": ""e2"",
+ ""Manager"": null
+ },
+ ""Three"": {
+ ""$ref"": ""1""
+ },
+ ""Four"": {
+ ""$ref"": ""2""
+ }
+}";
+
+ Dictionary<string, Employee> employees = JsonConvert.DeserializeObject<Dictionary<string, Employee>>(json);
+ Assert.AreEqual(4, employees.Count);
+
+ Employee e1 = employees["One"];
+ Employee e2 = employees["Two"];
+
+ Assert.AreEqual("e1", e1.Name);
+ Assert.AreEqual("e2", e2.Name);
+
+ Assert.AreEqual(e1, employees["Three"]);
+ Assert.AreEqual(e2, employees["Four"]);
+ }
+
+ public class CircularDictionary : Dictionary<string, CircularDictionary>
+ {
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Self referencing loop")]
+ public void SerializeCircularDictionarysError()
+ {
+ CircularDictionary circularDictionary = new CircularDictionary();
+ circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
+ circularDictionary.Add("self", circularDictionary);
+
+ JsonConvert.SerializeObject(circularDictionary, Formatting.Indented);
+ }
+
+ [Test]
+ public void SerializeCircularDictionarysIgnore()
+ {
+ CircularDictionary circularDictionary = new CircularDictionary();
+ circularDictionary.Add("other", new CircularDictionary { { "blah", null } });
+ circularDictionary.Add("self", circularDictionary);
+
+ string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
+ new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
+
+ Assert.AreEqual(@"{
+ ""other"": {
+ ""blah"": null
+ }
+}", json);
+ }
+
+ [Test]
+ public void SerializeDictionarysWithPreserveObjectReferences()
+ {
+ CircularDictionary circularDictionary = new CircularDictionary();
+ circularDictionary.Add("other", new CircularDictionary { {"blah", null }});
+ circularDictionary.Add("self", circularDictionary);
+
+ string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
+ new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
+
+ Assert.AreEqual(@"{
+ ""$id"": ""1"",
+ ""other"": {
+ ""$id"": ""2"",
+ ""blah"": null
+ },
+ ""self"": {
+ ""$ref"": ""1""
+ }
+}", json);
+ }
+
+ [Test]
+ public void DeserializeDictionarysWithPreserveObjectReferences()
+ {
+ string json = @"{
+ ""$id"": ""1"",
+ ""other"": {
+ ""$id"": ""2"",
+ ""blah"": null
+ },
+ ""self"": {
+ ""$ref"": ""1""
+ }
+}";
+
+ CircularDictionary circularDictionary = JsonConvert.DeserializeObject<CircularDictionary>(json,
+ new JsonSerializerSettings
+ {
+ PreserveReferencesHandling = PreserveReferencesHandling.All
+ });
+
+ Assert.AreEqual(2, circularDictionary.Count);
+ Assert.AreEqual(1, circularDictionary["other"].Count);
+ Assert.AreEqual(circularDictionary, circularDictionary["self"]);
+ }
+
+ public class CircularList : List<CircularList>
+ {
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Self referencing loop")]
+ public void SerializeCircularListsError()
+ {
+ CircularList circularList = new CircularList();
+ circularList.Add(null);
+ circularList.Add(new CircularList { null });
+ circularList.Add(new CircularList { new CircularList { circularList } });
+
+ JsonConvert.SerializeObject(circularList, Formatting.Indented);
+ }
+
+ [Test]
+ public void SerializeCircularListsIgnore()
+ {
+ CircularList circularList = new CircularList();
+ circularList.Add(null);
+ circularList.Add(new CircularList { null });
+ circularList.Add(new CircularList { new CircularList { circularList } });
+
+ string json = JsonConvert.SerializeObject(circularList,
+ Formatting.Indented,
+ new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
+
+ Assert.AreEqual(@"[
+ null,
+ [
+ null
+ ],
+ [
+ []
+ ]
+]", json);
+ }
+
+ [Test]
+ public void SerializeListsWithPreserveObjectReferences()
+ {
+ CircularList circularList = new CircularList();
+ circularList.Add(null);
+ circularList.Add(new CircularList { null });
+ circularList.Add(new CircularList { new CircularList { circularList }});
+
+ string json = JsonConvert.SerializeObject(circularList, Formatting.Indented,
+ new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
+
+ WriteEscapedJson(json);
+ Assert.AreEqual(@"{
+ ""$id"": ""1"",
+ ""value"": [
+ null,
+ {
+ ""$id"": ""2"",
+ ""value"": [
+ null
+ ]
+ },
+ {
+ ""$id"": ""3"",
+ ""value"": [
+ {
+ ""$id"": ""4"",
+ ""value"": [
+ {
+ ""$ref"": ""1""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}", json);
+ }
+
+ [Test]
+ public void DeserializeListsWithPreserveObjectReferences()
+ {
+ string json = @"{
+ ""$id"": ""1"",
+ ""value"": [
+ null,
+ {
+ ""$id"": ""2"",
+ ""value"": [
+ null
+ ]
+ },
+ {
+ ""$id"": ""3"",
+ ""value"": [
+ {
+ ""$id"": ""4"",
+ ""value"": [
+ {
+ ""$ref"": ""1""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}";
+
+ CircularList circularList = JsonConvert.DeserializeObject<CircularList>(json,
+ new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
+
+ Assert.AreEqual(3, circularList.Count);
+ Assert.AreEqual(null, circularList[0]);
+ Assert.AreEqual(1, circularList[1].Count);
+ Assert.AreEqual(1, circularList[2].Count);
+ Assert.AreEqual(1, circularList[2][0].Count);
+ Assert.IsTrue(ReferenceEquals(circularList, circularList[2][0][0]));
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot preserve reference to array or readonly list: System.String[][]")]
+ public void DeserializeArraysWithPreserveObjectReferences()
+ {
+ string json = @"{
+ ""$id"": ""1"",
+ ""value"": [
+ null,
+ {
+ ""$id"": ""2"",
+ ""value"": [
+ null
+ ]
+ },
+ {
+ ""$id"": ""3"",
+ ""value"": [
+ {
+ ""$id"": ""4"",
+ ""value"": [
+ {
+ ""$ref"": ""1""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}";
+
+ JsonConvert.DeserializeObject<string[][]>(json,
+ new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unexpected end when deserializing object.")]
+ public void UnexpectedEnd()
+ {
+ string json = @"{
+ ""$id"":";
+
+ JsonConvert.DeserializeObject<string[][]>(json,
+ new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
+ }
+
+ public class DictionaryInterfaceClass
+ {
+ public string Name { get; set; }
+ public IDictionary<string, int> Dictionary { get; set; }
+ public ICollection<int> Collection { get; set; }
+ public Employee Employee { get; set; }
+ public object Random { get; set; }
+
+ public DictionaryInterfaceClass()
+ {
+ Dictionary = new Dictionary<string, int>
+ {
+ { "existing", 1 }
+ };
+ Collection = new List<int>
+ {
+ 1,
+ 2,
+ 3
+ };
+ Employee = new Employee
+ {
+ Name = "EmployeeName!"
+ };
+ }
+ }
+
+ [Test]
+ public void DeserializeDictionaryInterface()
+ {
+ string json = @"{
+ ""Name"": ""Name!"",
+ ""Dictionary"": {
+ ""Item"": 11
+ }
+}";
+
+ DictionaryInterfaceClass c = JsonConvert.DeserializeObject<DictionaryInterfaceClass>(json,
+ new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace });
+ Assert.AreEqual("Name!", c.Name);
+ Assert.AreEqual(1, c.Dictionary.Count);
+ Assert.AreEqual(11, c.Dictionary["Item"]);
+ }
+
+ [Test]
+ public void DeserializeDictionaryInterfaceWithExistingValues()
+ {
+ string json = @"{
+ ""Random"": {
+ ""blah"": 1
+ },
+ ""Name"": ""Name!"",
+ ""Dictionary"": {
+ ""Item"": 11,
+ ""Item1"": 12
+ },
+ ""Collection"": [
+ 999
+ ],
+ ""Employee"": {
+ ""Manager"": {
+ ""Name"": ""ManagerName!""
+ }
+ }
+}";
+
+ DictionaryInterfaceClass c = JsonConvert.DeserializeObject<DictionaryInterfaceClass>(json,
+ new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Reuse });
+
+ Assert.AreEqual("Name!", c.Name);
+ Assert.AreEqual(3, c.Dictionary.Count);
+ Assert.AreEqual(11, c.Dictionary["Item"]);
+ Assert.AreEqual(1, c.Dictionary["existing"]);
+ Assert.AreEqual(4, c.Collection.Count);
+ Assert.AreEqual(1, c.Collection.ElementAt(0));
+ Assert.AreEqual(999, c.Collection.ElementAt(3));
+ Assert.AreEqual("EmployeeName!", c.Employee.Name);
+ Assert.AreEqual("ManagerName!", c.Employee.Manager.Name);
+ Assert.IsNotNull(c.Random);
+ }
+
+ public class CircularReferenceClassConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ CircularReferenceClass circularReferenceClass = (CircularReferenceClass) value;
+
+ string reference = serializer.ReferenceResolver.ResolveReference(circularReferenceClass);
+
+ JObject me = new JObject();
+ me["$id"] = new JValue(reference);
+ me["$type"] = new JValue(value.GetType().Name);
+ me["Name"] = new JValue(circularReferenceClass.Name);
+
+ JObject o = JObject.FromObject(circularReferenceClass.Child, serializer);
+ me["Child"] = o;
+
+ me.WriteTo(writer);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
+ {
+ JObject o = JObject.Load(reader);
+ string id = (string)o["$id"];
+ if (id != null)
+ {
+ CircularReferenceClass circularReferenceClass = new CircularReferenceClass();
+ serializer.Populate(o.CreateReader(), circularReferenceClass);
+ return circularReferenceClass;
+ }
+ else
+ {
+ string reference = (string)o["$ref"];
+ return serializer.ReferenceResolver.ResolveObject(reference);
+ }
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return (objectType == typeof(CircularReferenceClass));
+ }
+ }
+
+ [Test]
+ public void SerializeCircularReferencesWithConverter()
+ {
+ CircularReferenceClass c1 = new CircularReferenceClass { Name = "c1" };
+ CircularReferenceClass c2 = new CircularReferenceClass { Name = "c2" };
+ CircularReferenceClass c3 = new CircularReferenceClass { Name = "c3" };
+
+ c1.Child = c2;
+ c2.Child = c3;
+ c3.Child = c1;
+
+ string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
+ {
+ PreserveReferencesHandling = PreserveReferencesHandling.Objects,
+ Converters = new List<JsonConverter> { new CircularReferenceClassConverter() }
+ });
+
+ Assert.AreEqual(@"{
+ ""$id"": ""1"",
+ ""$type"": ""CircularReferenceClass"",
+ ""Name"": ""c1"",
+ ""Child"": {
+ ""$id"": ""2"",
+ ""$type"": ""CircularReferenceClass"",
+ ""Name"": ""c2"",
+ ""Child"": {
+ ""$id"": ""3"",
+ ""$type"": ""CircularReferenceClass"",
+ ""Name"": ""c3"",
+ ""Child"": {
+ ""$ref"": ""1""
+ }
+ }
+ }
+}", json);
+ }
+
+ [Test]
+ public void DeserializeCircularReferencesWithConverter()
+ {
+ string json = @"{
+ ""$id"": ""1"",
+ ""$type"": ""CircularReferenceClass"",
+ ""Name"": ""c1"",
+ ""Child"": {
+ ""$id"": ""2"",
+ ""$type"": ""CircularReferenceClass"",
+ ""Name"": ""c2"",
+ ""Child"": {
+ ""$id"": ""3"",
+ ""$type"": ""CircularReferenceClass"",
+ ""Name"": ""c3"",
+ ""Child"": {
+ ""$ref"": ""1""
+ }
+ }
+ }
+}";
+
+ CircularReferenceClass c1 = JsonConvert.DeserializeObject<CircularReferenceClass>(json, new JsonSerializerSettings
+ {
+ PreserveReferencesHandling = PreserveReferencesHandling.Objects,
+ Converters = new List<JsonConverter> { new CircularReferenceClassConverter() }
+ });
+
+ Assert.AreEqual("c1", c1.Name);
+ Assert.AreEqual("c2", c1.Child.Name);
+ Assert.AreEqual("c3", c1.Child.Child.Name);
+ Assert.AreEqual("c1", c1.Child.Child.Child.Name);
+ }
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs b/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs
index 9187cbd..a6adc94 100644
--- a/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs
+++ b/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs
@@ -8,7 +8,7 @@ namespace Newtonsoft.Json.Tests.LinqToSql
{
public class DepartmentConverter : JsonConverter
{
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Department department = (Department)value;
@@ -19,7 +19,7 @@ namespace Newtonsoft.Json.Tests.LinqToSql
o.WriteTo(writer);
}
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
JObject o = JObject.Load(reader);
diff --git a/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs b/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs
index 79fa74b..e6d4a5f 100644
--- a/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs
+++ b/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs
@@ -7,13 +7,13 @@ namespace Newtonsoft.Json.Tests.LinqToSql
{
public class GuidByteArrayConverter : JsonConverter
{
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Guid guid = (Guid) value;
writer.WriteValue(Convert.ToBase64String(guid.ToByteArray()));
}
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
string encodedData = (string) reader.Value;
byte[] data = Convert.FromBase64String(encodedData);
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj
index 288c3b8..a3b2a10 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj
@@ -80,6 +80,7 @@
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
+ <Compile Include="TestObjects\Employee.cs" />
<Compile Include="TestObjects\GenericImpl.cs" />
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj
index 6f8e38b..741733a 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj
@@ -84,6 +84,7 @@
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
+ <Compile Include="TestObjects\Employee.cs" />
<Compile Include="TestObjects\GenericImpl.cs" />
<Compile Include="TestObjects\GenericListAndDictionaryInterfaceProperties.cs" />
<Compile Include="TestObjects\GetOnlyPropertyClass.cs" />
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 8e0ed9e..1420f8b 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -111,6 +111,7 @@
<Compile Include="TestObjects\ConverterPrecedenceClass.cs" />
<Compile Include="TestObjects\ConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\CircularReferenceWithIdClass.cs" />
+ <Compile Include="TestObjects\Employee.cs" />
<Compile Include="TestObjects\JsonPropertyWithHandlingValues.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
<Compile Include="TestObjects\DoubleClass.cs" />
diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
index 06eecdb..be102ab 100644
--- a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
+++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
@@ -41,7 +41,12 @@ namespace Newtonsoft.Json.Tests
// return utcOffset.Hours.ToString("+00;-00") + utcOffset.Minutes.ToString("00;00");
//}
- protected string EscapedJson(string json)
+ protected void WriteEscapedJson(string json)
+ {
+ Console.WriteLine(EscapeJson(json));
+ }
+
+ protected string EscapeJson(string json)
{
return @"@""" + json.Replace(@"""", @"""""") + @"""";
}
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs
index 7f58798..f22f27d 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs
@@ -34,7 +34,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
{
public abstract string ConverterType { get; }
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
ConverterPrecedenceClass c = (ConverterPrecedenceClass)value;
@@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
j.WriteTo(writer);
}
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
JToken j = JArray.Load(reader);
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Employee.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Employee.cs
new file mode 100644
index 0000000..938dfb5
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/Employee.cs
@@ -0,0 +1,39 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Tests.TestObjects
+{
+ [JsonObject(IsReference = true)]
+ public class Employee
+ {
+ public string Name { get; set; }
+ public Employee Manager { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs
index c62f948..ddc8402 100644
--- a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/BinaryConverter.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;
#if !SILVERLIGHT && !PocketPC
using System.Data.Linq;
@@ -23,7 +48,7 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
@@ -58,7 +83,7 @@ namespace Newtonsoft.Json.Converters
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <returns>The object value.</returns>
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
Type t = (ReflectionUtils.IsNullableType(objectType))
? Nullable.GetUnderlyingType(objectType)
diff --git a/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs b/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs
new file mode 100644
index 0000000..00a2dcd
--- /dev/null
+++ b/Src/Newtonsoft.Json/Converters/CustomCreationConverter.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.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Converters
+{
+ public abstract class CustomCreationConverter<T> : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
+ {
+ T value = Create();
+ if (value == null)
+ throw new JsonSerializationException("No object created.");
+
+ serializer.Populate(reader, value);
+ return value;
+ }
+
+ public abstract T Create();
+
+ public override bool CanConvert(Type objectType)
+ {
+ return typeof (T).IsAssignableFrom(objectType);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs
index 054f320..de0e6dc 100644
--- a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs
@@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(ColorTranslator.ToHtml((Color)value));
}
@@ -64,7 +64,7 @@ namespace Newtonsoft.Json.Converters
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <returns>The object value.</returns>
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
throw new NotImplementedException();
}
diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
index fa834a9..c9aed91 100644
--- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
@@ -53,7 +53,8 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public override void WriteJson(JsonWriter writer, object value)
+ /// <param name="serializer">The calling serializer.</param>
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
string text;
@@ -89,8 +90,9 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
+ /// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
Type t = (ReflectionUtils.IsNullableType(objectType))
? Nullable.GetUnderlyingType(objectType)
diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs
index 9ac9588..91e869b 100644
--- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs
@@ -17,7 +17,7 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
long ticks;
@@ -45,7 +45,7 @@ namespace Newtonsoft.Json.Converters
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <returns>The object value.</returns>
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
Type t = (ReflectionUtils.IsNullableType(objectType))
? Nullable.GetUnderlyingType(objectType)
diff --git a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs
index 19ccc60..e9fc1bf 100644
--- a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/StringEnumConverter.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.Linq;
using System.Text;
@@ -18,7 +43,7 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
@@ -41,7 +66,7 @@ namespace Newtonsoft.Json.Converters
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <returns>The object value.</returns>
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
Type t = (ReflectionUtils.IsNullableType(objectType))
? Nullable.GetUnderlyingType(objectType)
diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
index 4694ada..e840e00 100644
--- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
@@ -54,7 +54,7 @@ namespace Newtonsoft.Json.Converters
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public override void WriteJson(JsonWriter writer, object value)
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
XmlNode node = value as XmlNode;
@@ -261,7 +261,7 @@ namespace Newtonsoft.Json.Converters
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <returns>The object value.</returns>
- public override object ReadJson(JsonReader reader, Type objectType)
+ public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
// maybe have CanReader and a CanWrite methods so this sort of test wouldn't be necessary
if (objectType != typeof(XmlDocument))
diff --git a/Src/Newtonsoft.Json/JsonContainerAttribute.cs b/Src/Newtonsoft.Json/JsonContainerAttribute.cs
index bb88c16..bc22365 100644
--- a/Src/Newtonsoft.Json/JsonContainerAttribute.cs
+++ b/Src/Newtonsoft.Json/JsonContainerAttribute.cs
@@ -40,6 +40,16 @@ namespace Newtonsoft.Json
public string Title { get; set; }
public string Description { get; set; }
+ // yuck. can't set nullable properties on an attribute in C#
+ // have to use this approach to get an unset default state
+ internal bool? _isReference;
+
+ public bool IsReference
+ {
+ get { return _isReference ?? default(bool); }
+ set { _isReference = value; }
+ }
+
/// <summary>
/// Initializes a new instance of the <see cref="JsonContainerAttribute"/> class.
/// </summary>
diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs
index 1bc9f11..27f356c 100644
--- a/Src/Newtonsoft.Json/JsonConverter.cs
+++ b/Src/Newtonsoft.Json/JsonConverter.cs
@@ -40,15 +40,17 @@ namespace Newtonsoft.Json
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
- public abstract void WriteJson(JsonWriter writer, object value);
+ /// <param name="serializer">The calling serializer.</param>
+ public abstract void WriteJson(JsonWriter writer, object value, JsonSerializer serializer);
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
+ /// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
- public abstract object ReadJson(JsonReader reader, Type objectType);
+ public abstract object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer);
/// <summary>
/// Determines whether this instance can convert the specified object type.
diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs
index dfa2557..e929f0e 100644
--- a/Src/Newtonsoft.Json/JsonSerializer.cs
+++ b/Src/Newtonsoft.Json/JsonSerializer.cs
@@ -25,17 +25,9 @@
using System;
using System.Collections.Generic;
-using System.Text;
using System.IO;
-using System.Collections;
-using System.Reflection;
-using System.ComponentModel;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
-using System.Globalization;
-using System.Linq;
-using Newtonsoft.Json.Linq;
-using System.Collections.ObjectModel;
namespace Newtonsoft.Json
{
@@ -46,6 +38,7 @@ namespace Newtonsoft.Json
public class JsonSerializer
{
#region Properties
+ private PreserveReferencesHandling _preserveReferencesHandling;
private ReferenceLoopHandling _referenceLoopHandling;
private MissingMemberHandling _missingMemberHandling;
private ObjectCreationHandling _objectCreationHandling;
@@ -53,11 +46,42 @@ namespace Newtonsoft.Json
private DefaultValueHandling _defaultValueHandling;
private JsonConverterCollection _converters;
private IMappingResolver _mappingResolver;
+ private IReferenceResolver _referenceResolver;
+
+ public virtual IReferenceResolver ReferenceResolver
+ {
+ get
+ {
+ if (_referenceResolver == null)
+ _referenceResolver = new DefaultReferenceResolver();
+
+ return _referenceResolver;
+ }
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException("value", "Reference resolver cannot be null.");
+
+ _referenceResolver = value;
+ }
+ }
+
+ public virtual PreserveReferencesHandling PreserveReferencesHandling
+ {
+ get { return _preserveReferencesHandling; }
+ set
+ {
+ if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
+ throw new ArgumentOutOfRangeException("value");
+
+ _preserveReferencesHandling = value;
+ }
+ }
/// <summary>
/// Get or set how reference loops (e.g. a class referencing itself) is handled.
/// </summary>
- public ReferenceLoopHandling ReferenceLoopHandling
+ public virtual ReferenceLoopHandling ReferenceLoopHandling
{
get { return _referenceLoopHandling; }
set
@@ -72,7 +96,7 @@ namespace Newtonsoft.Json
/// <summary>
/// Get or set how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization.
/// </summary>
- public MissingMemberHandling MissingMemberHandling
+ public virtual MissingMemberHandling MissingMemberHandling
{
get { return _missingMemberHandling; }
set
@@ -87,7 +111,7 @@ namespace Newtonsoft.Json
/// <summary>
/// Get or set how null values are handled during serialization and deserialization.
/// </summary>
- public NullValueHandling NullValueHandling
+ public virtual NullValueHandling NullValueHandling
{
get { return _nullValueHandling; }
set
@@ -102,7 +126,7 @@ namespace Newtonsoft.Json
/// <summary>
/// Get or set how null default are handled during serialization and deserialization.
/// </summary>
- public DefaultValueHandling DefaultValueHandling
+ public virtual DefaultValueHandling DefaultValueHandling
{
get { return _defaultValueHandling; }
set
@@ -118,7 +142,7 @@ namespace Newtonsoft.Json
/// Gets or sets how objects are created during deserialization.
/// </summary>
/// <value>The object creation handling.</value>
- public ObjectCreationHandling ObjectCreationHandling
+ public virtual ObjectCreationHandling ObjectCreationHandling
{
get { return _objectCreationHandling; }
set
@@ -134,7 +158,7 @@ namespace Newtonsoft.Json
/// Gets a collection <see cref="JsonConverter"/> that will be used during serialization.
/// </summary>
/// <value>Collection <see cref="JsonConverter"/> that will be used during serialization.</value>
- public JsonConverterCollection Converters
+ public virtual JsonConverterCollection Converters
{
get
{
@@ -145,7 +169,7 @@ namespace Newtonsoft.Json
}
}
- public IMappingResolver MappingResolver
+ public virtual IMappingResolver MappingResolver
{
get { return _mappingResolver; }
set { _mappingResolver = value; }
@@ -164,7 +188,6 @@ namespace Newtonsoft.Json
_objectCreationHandling = JsonSerializerSettings.DefaultObjectCreationHandling;
}
-
/// <summary>
/// Creates a new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/> objects.
/// </summary>
@@ -179,6 +202,7 @@ namespace Newtonsoft.Json
if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
jsonSerializer.Converters.AddRange(settings.Converters);
+ jsonSerializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
jsonSerializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
jsonSerializer.MissingMemberHandling = settings.MissingMemberHandling;
jsonSerializer.ObjectCreationHandling = settings.ObjectCreationHandling;
@@ -190,7 +214,25 @@ namespace Newtonsoft.Json
return jsonSerializer;
}
- #region Deserialize
+ public void Populate(TextReader reader, object target)
+ {
+ Populate(new JsonTextReader(reader), target);
+ }
+
+ public void Populate(JsonReader reader, object target)
+ {
+ PopulateInternal(reader, target);
+ }
+
+ internal virtual void PopulateInternal(JsonReader reader, object target)
+ {
+ ValidationUtils.ArgumentNotNull(reader, "reader");
+ ValidationUtils.ArgumentNotNull(target, "target");
+
+ JsonSerializerReader serializerReader = new JsonSerializerReader(this);
+ serializerReader.Populate(reader, target);
+ }
+
/// <summary>
/// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>.
/// </summary>
@@ -202,495 +244,37 @@ namespace Newtonsoft.Json
}
/// <summary>
- /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>
+ /// Deserializes the Json structure contained by the specified <see cref="StringReader"/>
/// into an instance of the specified type.
/// </summary>
- /// <param name="reader">The <see cref="JsonReader"/> containing the object.</param>
+ /// <param name="reader">The <see cref="TextReader"/> containing the object.</param>
/// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
/// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
- public object Deserialize(JsonReader reader, Type objectType)
+ public object Deserialize(TextReader reader, Type objectType)
{
- if (reader == null)
- throw new ArgumentNullException("reader");
-
- if (!reader.Read())
- return null;
-
- if (objectType != null)
- return CreateObject(reader, objectType, null, null);
- else
- return CreateJToken(reader);
+ return Deserialize(new JsonTextReader(reader), objectType);
}
/// <summary>
- /// Deserializes the Json structure contained by the specified <see cref="StringReader"/>
+ /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>
/// into an instance of the specified type.
/// </summary>
- /// <param name="reader">The <see cref="TextReader"/> containing the object.</param>
+ /// <param name="reader">The <see cref="JsonReader"/> containing the object.</param>
/// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
/// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
- public object Deserialize(TextReader reader, Type objectType)
- {
- return Deserialize(new JsonTextReader(reader), objectType);
- }
-
- private JToken CreateJToken(JsonReader reader)
- {
- JToken token;
- using (JTokenWriter writer = new JTokenWriter())
- {
- writer.WriteToken(reader);
- token = writer.Token;
- }
-
- return token;
- }
-
- private bool HasClassConverter(Type objectType, out JsonConverter converter)
- {
- if (objectType == null)
- throw new ArgumentNullException("objectType");
-
- converter = JsonTypeReflector.GetConverter(objectType, objectType);
- return (converter != null);
- }
-
- private object CreateObject(JsonReader reader, Type objectType, object existingValue, JsonConverter memberConverter)
- {
- object value;
- JsonConverter converter;
-
- if (memberConverter != null)
- {
- return memberConverter.ReadJson(reader, objectType);
- }
- else if (objectType != null && HasClassConverter(objectType, out converter))
- {
- return converter.ReadJson(reader, objectType);
- }
- else if (objectType != null && HasMatchingConverter(objectType, out converter))
- {
- return converter.ReadJson(reader, objectType);
- }
- else if (objectType == typeof(JsonRaw))
- {
- return JsonRaw.Create(reader);
- }
- else
- {
- switch (reader.TokenType)
- {
- // populate a typed object or generic dictionary/array
- // depending upon whether an objectType was supplied
- case JsonToken.StartObject:
- if (objectType == null)
- {
- value = CreateJToken(reader);
- }
- else if (CollectionUtils.IsDictionaryType(objectType))
- {
- if (existingValue == null)
- value = CreateAndPopulateDictionary(reader, objectType);
- else
- value = PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader);
- }
- else
- {
- if (existingValue == null)
- value = CreateAndPopulateObject(reader, objectType);
- else
- value = PopulateObject(existingValue, reader, objectType);
- }
- break;
- case JsonToken.StartArray:
- if (objectType != null)
- {
- if (existingValue == null)
- value = CreateAndPopulateList(reader, objectType);
- else
- value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), ReflectionUtils.GetCollectionItemType(objectType), reader);
- }
- else
- {
- value = CreateJToken(reader);
- }
- break;
- case JsonToken.Integer:
- case JsonToken.Float:
- case JsonToken.String:
- case JsonToken.Boolean:
- case JsonToken.Date:
- value = EnsureType(reader.Value, objectType);
- break;
- case JsonToken.StartConstructor:
- case JsonToken.EndConstructor:
- string constructorName = reader.Value.ToString();
-
- value = constructorName;
- break;
- case JsonToken.Null:
- case JsonToken.Undefined:
- if (objectType == typeof(DBNull))
- value = DBNull.Value;
- else
- value = null;
- break;
- default:
- throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
- }
- }
-
- return value;
- }
-
- private object EnsureType(object value, Type targetType)
- {
- // do something about null value when the targetType is a valuetype?
- if (value == null)
- return null;
-
- if (targetType == null)
- return value;
-
- Type valueType = value.GetType();
-
- // type of value and type of target don't match
- // attempt to convert value's type to target's type
- if (valueType != targetType)
- {
- return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
- }
- else
- {
- return value;
- }
- }
-
- private JsonMemberMappingCollection GetMemberMappings(Type objectType)
- {
- ValidationUtils.ArgumentNotNull(objectType, "objectType");
-
- if (_mappingResolver != null)
- return _mappingResolver.ResolveMappings(objectType);
-
- return DefaultMappingResolver.Instance.ResolveMappings(objectType);
- }
-
- private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName)
- {
- JsonMemberMappingCollection memberMappings = GetMemberMappings(targetType);
-
- JsonMemberMapping memberMapping;
- // attempt exact case match first
- // then try match ignoring case
- if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
- {
- SetMappingValue(memberMapping, reader, target);
- }
- else
- {
- if (_missingMemberHandling == MissingMemberHandling.Error)
- throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, targetType.Name));
-
- reader.Skip();
- }
- }
-
- private void SetMappingValue(JsonMemberMapping memberMapping, JsonReader reader, object target)
- {
- if (memberMapping.Ignored)
- {
- reader.Skip();
- return;
- }
-
- // get the member's underlying type
- Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
-
- object currentValue = null;
- bool useExistingValue = false;
-
- if ((_objectCreationHandling == ObjectCreationHandling.Auto || _objectCreationHandling == ObjectCreationHandling.Reuse)
- && (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
- {
- currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
-
- useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericDefinition(memberType, typeof(ReadOnlyCollection<>)));
- }
-
- if (!memberMapping.Writable && !useExistingValue)
- {
- reader.Skip();
- return;
- }
-
- object value = CreateObject(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(memberMapping.Member, memberType));
-
- if (!useExistingValue && ShouldSetMappingValue(memberMapping, value))
- ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
- }
-
- private bool ShouldSetMappingValue(JsonMemberMapping memberMapping, object value)
- {
- if (memberMapping.NullValueHandling.GetValueOrDefault(_nullValueHandling) == NullValueHandling.Ignore && value == null)
- return false;
-
- if (memberMapping.DefaultValueHandling.GetValueOrDefault(_defaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, memberMapping.DefaultValue))
- return false;
-
- if (!memberMapping.Writable)
- return false;
-
- return true;
- }
-
- private object CreateAndPopulateDictionary(JsonReader reader, Type objectType)
- {
- if (IsTypeGenericDictionaryInterface(objectType))
- {
- Type keyType;
- Type valueType;
- ReflectionUtils.GetDictionaryKeyValueTypes(objectType, out keyType, out valueType);
- objectType = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
- }
-
- IWrappedDictionary dictionary = CollectionUtils.CreateDictionaryWrapper(Activator.CreateInstance(objectType));
- PopulateDictionary(dictionary, reader);
-
- return dictionary.UnderlyingDictionary;
- }
-
- private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader)
- {
- Type dictionaryType = dictionary.UnderlyingDictionary.GetType();
- Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryType);
- Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryType);
-
- while (reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.PropertyName:
- object keyValue = EnsureType(reader.Value, dictionaryKeyType);
- reader.Read();
-
- dictionary.Add(keyValue, CreateObject(reader, dictionaryValueType, null, null));
- break;
- case JsonToken.EndObject:
- return dictionary;
- default:
- throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
- }
- }
-
- throw new JsonSerializationException("Unexpected end when deserializing object.");
- }
-
- private object CreateAndPopulateList(JsonReader reader, Type objectType)
- {
- if (IsTypeGenericCollectionInterface(objectType))
- {
- Type itemType = ReflectionUtils.GetCollectionItemType(objectType);
- objectType = ReflectionUtils.MakeGenericType(typeof(List<>), itemType);
- }
-
- return CollectionUtils.CreateAndPopulateList(objectType, l => PopulateList(l, ReflectionUtils.GetCollectionItemType(objectType), reader));
- }
-
- private IList PopulateList(IList list, Type listItemType, JsonReader reader)
- {
- while (reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.EndArray:
- return list;
- case JsonToken.Comment:
- break;
- default:
- object value = CreateObject(reader, listItemType, null, null);
-
- list.Add(value);
- break;
- }
- }
-
- throw new JsonSerializationException("Unexpected end when deserializing array.");
- }
-
- private bool IsTypeGenericDictionaryInterface(Type type)
- {
- if (!type.IsGenericType)
- return false;
-
- Type genericDefinition = type.GetGenericTypeDefinition();
-
- return (genericDefinition == typeof (IDictionary<,>));
- }
-
- private bool IsTypeGenericCollectionInterface(Type type)
- {
- if (!type.IsGenericType)
- return false;
-
- Type genericDefinition = type.GetGenericTypeDefinition();
-
- return (genericDefinition == typeof (IList<>)
- || genericDefinition == typeof (ICollection<>)
- || genericDefinition == typeof (IEnumerable<>));
- }
-
- private object CreateAndPopulateObject(JsonReader reader, Type objectType)
- {
- object newObject;
-
- if (objectType.IsInterface || objectType.IsAbstract)
- throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, objectType));
-
- if (ReflectionUtils.HasDefaultConstructor(objectType))
- {
- newObject = Activator.CreateInstance(objectType);
-
- PopulateObject(newObject, reader, objectType);
- return newObject;
- }
-
- return CreateObjectFromNonDefaultConstructor(objectType, reader);
- }
-
- private object CreateObjectFromNonDefaultConstructor(Type objectType, JsonReader reader)
+ public object Deserialize(JsonReader reader, Type objectType)
{
- // object should have a single constructor
- ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
-
- if (c == null)
- throw new JsonSerializationException("Could not find a public constructor for type {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
-
- // create a dictionary to put retrieved values into
- JsonMemberMappingCollection memberMappings = GetMemberMappings(objectType);
- IDictionary<JsonMemberMapping, object> mappingValues = memberMappings.ToDictionary(kv => kv, kv => (object)null);
-
- bool exit = false;
- while (!exit && reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.PropertyName:
- string memberName = reader.Value.ToString();
- if (!reader.Read())
- throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
-
- JsonMemberMapping memberMapping;
- // attempt exact case match first
- // then try match ignoring case
- if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
- {
- if (!memberMapping.Ignored)
- {
- Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
- mappingValues[memberMapping] = CreateObject(reader, memberType, null, memberMapping.MemberConverter);
- }
- }
- else
- {
- if (_missingMemberHandling == MissingMemberHandling.Error)
- throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
-
- reader.Skip();
- }
- break;
- case JsonToken.EndObject:
- exit = true;
- break;
- default:
- throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
- }
- }
-
- IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
- IDictionary<JsonMemberMapping, object> remainingMappingValues = new Dictionary<JsonMemberMapping, object>();
-
- foreach (KeyValuePair<JsonMemberMapping, object> mappingValue in mappingValues)
- {
- ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, mappingValue.Key.MappingName).Key;
- if (matchingConstructorParameter != null)
- constructorParameters[matchingConstructorParameter] = mappingValue.Value;
- else
- remainingMappingValues.Add(mappingValue);
- }
-
- object createdObject = ReflectionUtils.CreateInstance(objectType, constructorParameters.Values.ToArray());
-
- // go through unused values and set the newly created object's properties
- foreach (KeyValuePair<JsonMemberMapping, object> remainingMappingValue in remainingMappingValues)
- {
- if (ShouldSetMappingValue(remainingMappingValue.Key, remainingMappingValue.Value))
- ReflectionUtils.SetMemberValue(remainingMappingValue.Key.Member, createdObject, remainingMappingValue.Value);
- }
-
- return createdObject;
+ return DeserializeInternal(reader, objectType);
}
- private object PopulateObject(object newObject, JsonReader reader, Type objectType)
+ internal virtual object DeserializeInternal(JsonReader reader, Type objectType)
{
- JsonMemberMappingCollection memberMappings = GetMemberMappings(objectType);
- Dictionary<string, bool> requiredMappings =
- memberMappings.Where(m => m.Required).ToDictionary(m => m.MappingName, m => false);
-
- while (reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.PropertyName:
- string memberName = reader.Value.ToString();
-
- if (!reader.Read())
- throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
-
- if (reader.TokenType != JsonToken.Null)
- SetRequiredMapping(memberName, requiredMappings);
-
- SetObjectMember(reader, newObject, objectType, memberName);
- break;
- case JsonToken.EndObject:
- foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
- {
- if (!requiredMapping.Value)
- throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredMapping.Key));
- }
- return newObject;
- default:
- throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
- }
- }
+ ValidationUtils.ArgumentNotNull(reader, "reader");
- throw new JsonSerializationException("Unexpected end when deserializing object.");
- }
-
- private void SetRequiredMapping(string memberName, Dictionary<string, bool> requiredMappings)
- {
- // first attempt to find exact case match
- // then attempt case insensitive match
- if (requiredMappings.ContainsKey(memberName))
- {
- requiredMappings[memberName] = true;
- }
- else
- {
- foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
- {
- if (string.Compare(requiredMapping.Key, requiredMapping.Key, StringComparison.OrdinalIgnoreCase) == 0)
- {
- requiredMappings[requiredMapping.Key] = true;
- break;
- }
- }
- }
+ JsonSerializerReader serializerReader = new JsonSerializerReader(this);
+ return serializerReader.Deserialize(reader, objectType);
}
- #endregion
-
- #region Serialize
/// <summary>
/// Serializes the specified <see cref="Object"/> and writes the Json structure
/// to a <c>Stream</c> using the specified <see cref="TextWriter"/>.
@@ -710,67 +294,37 @@ namespace Newtonsoft.Json
/// <param name="value">The <see cref="Object"/> to serialize.</param>
public void Serialize(JsonWriter jsonWriter, object value)
{
- if (jsonWriter == null)
- throw new ArgumentNullException("jsonWriter");
+ SerializeInternal(jsonWriter, value);
+ }
+
+ internal virtual void SerializeInternal(JsonWriter jsonWriter, object value)
+ {
+ ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
- if (value is JToken)
- ((JToken)value).WriteTo(jsonWriter, (_converters != null) ? _converters.ToArray() : null);
- else
- SerializeValue(jsonWriter, value, null);
+ JsonSerializerWriter serializerWriter = new JsonSerializerWriter(this);
+ serializerWriter.Serialize(jsonWriter, value);
}
+ internal bool HasClassConverter(Type objectType, out JsonConverter converter)
+ {
+ if (objectType == null)
+ throw new ArgumentNullException("objectType");
- private void SerializeValue(JsonWriter writer, object value, JsonConverter memberConverter)
+ converter = JsonTypeReflector.GetConverter(objectType, objectType);
+ return (converter != null);
+ }
+
+ internal JsonMemberMappingCollection GetMemberMappings(Type objectType)
{
- JsonConverter converter;
+ ValidationUtils.ArgumentNotNull(objectType, "objectType");
- if (value == null)
- {
- writer.WriteNull();
- }
- else if (memberConverter != null)
- {
- memberConverter.WriteJson(writer, value);
- }
- else if (HasClassConverter(value.GetType(), out converter))
- {
- converter.WriteJson(writer, value);
- }
- else if (HasMatchingConverter(value.GetType(), out converter))
- {
- converter.WriteJson(writer, value);
- }
- else if (JsonConvert.IsJsonPrimitive(value))
- {
- writer.WriteValue(value);
- }
- else if (value is IList)
- {
- SerializeList(writer, (IList)value);
- }
- else if (value is IDictionary)
- {
- SerializeDictionary(writer, (IDictionary)value);
- }
- else if (value is ICollection)
- {
- SerializeCollection(writer, (ICollection)value);
- }
- else if (value is IEnumerable)
- {
- SerializeEnumerable(writer, (IEnumerable)value);
- }
- else if (value is JsonRaw)
- {
- writer.WriteRawValue(((JsonRaw)value).Content);
- }
- else
- {
- SerializeObject(writer, value);
- }
+ if (_mappingResolver != null)
+ return _mappingResolver.ResolveMappings(objectType);
+
+ return DefaultMappingResolver.Instance.ResolveMappings(objectType);
}
- private bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
+ internal bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
{
return HasMatchingConverter(_converters, type, out matchingConverter);
}
@@ -797,121 +351,5 @@ namespace Newtonsoft.Json
matchingConverter = null;
return false;
}
-
- private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonMemberMapping memberMapping)
- {
- MemberInfo member = memberMapping.Member;
- string propertyName = memberMapping.MappingName;
- JsonConverter memberConverter = memberMapping.MemberConverter;
- object defaultValue = memberMapping.DefaultValue;
-
- if (!ReflectionUtils.IsIndexedProperty(member))
- {
- object memberValue = ReflectionUtils.GetMemberValue(member, value);
-
- if (memberMapping.NullValueHandling.GetValueOrDefault(_nullValueHandling) == NullValueHandling.Ignore && memberValue == null)
- return;
-
- if (memberMapping.DefaultValueHandling.GetValueOrDefault(_defaultValueHandling) == DefaultValueHandling.Ignore && object.Equals(memberValue, defaultValue))
- return;
-
- if (writer.SerializeStack.IndexOf(memberValue) != -1)
- {
- switch (memberMapping.ReferenceLoopHandling.GetValueOrDefault(_referenceLoopHandling))
- {
- case ReferenceLoopHandling.Error:
- throw new JsonSerializationException("Self referencing loop");
- case ReferenceLoopHandling.Ignore:
- // return from method
- return;
- case ReferenceLoopHandling.Serialize:
- // continue
- break;
- default:
- throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, _referenceLoopHandling));
- }
- }
-
- writer.WritePropertyName(propertyName ?? member.Name);
- SerializeValue(writer, memberValue, memberConverter);
- }
- }
-
- private void SerializeObject(JsonWriter writer, object value)
- {
- Type objectType = value.GetType();
-
-#if !SILVERLIGHT && !PocketPC
- TypeConverter converter = TypeDescriptor.GetConverter(objectType);
-
- // use the objectType's TypeConverter if it has one and can convert to a string
- if (converter != null && !(converter is ComponentConverter) && (converter.GetType() != typeof(TypeConverter) || value is Type))
- {
- if (converter.CanConvertTo(typeof(string)))
- {
- writer.WriteValue(converter.ConvertToInvariantString(value));
- return;
- }
- }
-#else
- if (value is Guid || value is Type)
- {
- writer.WriteValue(value.ToString());
- return;
- }
-#endif
-
- writer.SerializeStack.Add(value);
-
- writer.WriteStartObject();
-
- JsonMemberMappingCollection memberMappings = GetMemberMappings(objectType);
-
- foreach (JsonMemberMapping memberMapping in memberMappings)
- {
- if (!memberMapping.Ignored && memberMapping.Readable)
- WriteMemberInfoProperty(writer, value, memberMapping);
- }
-
- writer.WriteEndObject();
-
- writer.SerializeStack.RemoveAt(writer.SerializeStack.Count - 1);
- }
-
- private void SerializeEnumerable(JsonWriter writer, IEnumerable values)
- {
- SerializeList(writer, values.Cast<object>().ToList());
- }
-
- private void SerializeCollection(JsonWriter writer, ICollection values)
- {
- SerializeList(writer, values.Cast<object>().ToList());
- }
-
- private void SerializeList(JsonWriter writer, IList values)
- {
- writer.WriteStartArray();
-
- for (int i = 0; i < values.Count; i++)
- {
- SerializeValue(writer, values[i], null);
- }
-
- writer.WriteEndArray();
- }
-
- private void SerializeDictionary(JsonWriter writer, IDictionary values)
- {
- writer.WriteStartObject();
-
- foreach (DictionaryEntry entry in values)
- {
- writer.WritePropertyName(entry.Key.ToString());
- SerializeValue(writer, entry.Value, null);
- }
-
- writer.WriteEndObject();
- }
- #endregion
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/JsonSerializerSettings.cs b/Src/Newtonsoft.Json/JsonSerializerSettings.cs
index 7d23f01..be76682 100644
--- a/Src/Newtonsoft.Json/JsonSerializerSettings.cs
+++ b/Src/Newtonsoft.Json/JsonSerializerSettings.cs
@@ -17,6 +17,7 @@ namespace Newtonsoft.Json
internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;
internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;
internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;
+ internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;
/// <summary>
/// Gets or sets how reference loops (e.g. a class referencing itself) is handled.
@@ -49,6 +50,7 @@ namespace Newtonsoft.Json
/// <value>The converters.</value>
public IList<JsonConverter> Converters { get; set; }
public IMappingResolver MappingResolver { get; set; }
+ public PreserveReferencesHandling PreserveReferencesHandling { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonSerializerSettings"/> class.
@@ -60,6 +62,7 @@ namespace Newtonsoft.Json
ObjectCreationHandling = DefaultObjectCreationHandling;
NullValueHandling = DefaultNullValueHandling;
DefaultValueHandling = DefaultDefaultValueHandling;
+ PreserveReferencesHandling = DefaultPreserveReferencesHandling;
Converters = new List<JsonConverter>();
}
}
diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs
index 9911102..b03078d 100644
--- a/Src/Newtonsoft.Json/JsonWriter.cs
+++ b/Src/Newtonsoft.Json/JsonWriter.cs
@@ -121,21 +121,9 @@ namespace Newtonsoft.Json
private int _top;
- private List<JTokenType> _stack;
+ private readonly List<JTokenType> _stack;
private State _currentState;
private Formatting _formatting;
- private List<object> _serializeStack;
-
- internal List<object> SerializeStack
- {
- get
- {
- if (_serializeStack == null)
- _serializeStack = new List<object>();
-
- return _serializeStack;
- }
- }
/// <summary>
/// Gets the top.
diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs
index d233055..726550a 100644
--- a/Src/Newtonsoft.Json/Linq/JArray.cs
+++ b/Src/Newtonsoft.Json/Linq/JArray.cs
@@ -138,6 +138,7 @@ namespace Newtonsoft.Json.Linq
throw new ArgumentException("An item of type {0} cannot be added to content.".FormatWith(CultureInfo.InvariantCulture, o.Type));
}
+
/// <summary>
/// Creates a <see cref="JArray"/> from an object.
/// </summary>
@@ -145,7 +146,12 @@ namespace Newtonsoft.Json.Linq
/// <returns>A <see cref="JArray"/> with the values of the specified object</returns>
public static new JArray FromObject(object o)
{
- JToken token = FromObjectInternal(o);
+ return FromObject(o, new JsonSerializer());
+ }
+
+ public static new JArray FromObject(object o, JsonSerializer jsonSerializer)
+ {
+ JToken token = FromObjectInternal(o, jsonSerializer);
if (token.Type != JTokenType.Array)
throw new ArgumentException("Object serialized to {0}. JArray instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type));
diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs
index 8d1c156..2a4d500 100644
--- a/Src/Newtonsoft.Json/Linq/JObject.cs
+++ b/Src/Newtonsoft.Json/Linq/JObject.cs
@@ -219,6 +219,7 @@ namespace Newtonsoft.Json.Linq
return Load(jsonReader);
}
+
/// <summary>
/// Creates a <see cref="JObject"/> from an object.
/// </summary>
@@ -226,14 +227,20 @@ namespace Newtonsoft.Json.Linq
/// <returns>A <see cref="JObject"/> with the values of the specified object</returns>
public static new JObject FromObject(object o)
{
- JToken token = FromObjectInternal(o);
+ return FromObject(o, new JsonSerializer());
+ }
- if (token.Type != JTokenType.Object)
+ public static new JObject FromObject(object o, JsonSerializer jsonSerializer)
+ {
+ JToken token = FromObjectInternal(o, jsonSerializer);
+
+ if (token != null && token.Type != JTokenType.Object)
throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type));
return (JObject)token;
}
+
internal override void ValidateObject(JToken o, JToken previous)
{
ValidationUtils.ArgumentNotNull(o, "o");
diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs
index e539590..432d71c 100644
--- a/Src/Newtonsoft.Json/Linq/JToken.cs
+++ b/Src/Newtonsoft.Json/Linq/JToken.cs
@@ -760,11 +760,10 @@ namespace Newtonsoft.Json.Linq
return new JTokenReader(this);
}
- internal static JToken FromObjectInternal(object o)
+ internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerializer)
{
ValidationUtils.ArgumentNotNull(o, "o");
-
- JsonSerializer jsonSerializer = new JsonSerializer();
+ ValidationUtils.ArgumentNotNull(jsonSerializer, "jsonSerializer");
JToken token;
using (JTokenWriter jsonWriter = new JTokenWriter())
@@ -783,7 +782,12 @@ namespace Newtonsoft.Json.Linq
/// <returns>A <see cref="JToken"/> with the value of the specified object</returns>
public static JToken FromObject(object o)
{
- return FromObjectInternal(o);
+ return FromObjectInternal(o, new JsonSerializer());
+ }
+
+ public static JToken FromObject(object o, JsonSerializer jsonSerializer)
+ {
+ return FromObjectInternal(o, jsonSerializer);
}
public static JToken ReadFrom(JsonReader reader)
diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs
index a9ab3e8..d564efe 100644
--- a/Src/Newtonsoft.Json/Linq/JValue.cs
+++ b/Src/Newtonsoft.Json/Linq/JValue.cs
@@ -269,7 +269,7 @@ namespace Newtonsoft.Json.Linq
JsonConverter matchingConverter;
if (value != null && JsonSerializer.HasMatchingConverter(converters, value.GetType(), out matchingConverter))
- matchingConverter.WriteJson(writer, value);
+ matchingConverter.WriteJson(writer, value, new JsonSerializer());
else
defaultWrite(value);
}
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
index 9be6a4f..94b464d 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
@@ -56,6 +56,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverter.cs" />
+ <Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="DateTimeOffset.cs" />
<Compile Include="IJsonLineInfo.cs" />
@@ -100,6 +101,7 @@
<Compile Include="Linq\JToken.cs" />
<Compile Include="Linq\JProperty.cs" />
<Compile Include="Linq\JValue.cs" />
+ <Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="Schema\Extensions.cs" />
<Compile Include="Schema\JsonSchemaException.cs" />
<Compile Include="Schema\JsonSchemaModel.cs" />
@@ -113,7 +115,9 @@
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
<Compile Include="Serialization\DefaultMappingResolver.cs" />
+ <Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="Serialization\IMappingResolver.cs" />
+ <Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Serialization\JsonMemberMapping.cs" />
<Compile Include="Serialization\JsonMemberMappingCollection.cs" />
<Compile Include="MissingMemberHandling.cs" />
@@ -125,7 +129,11 @@
<Compile Include="Schema\JsonSchemaGenerator.cs" />
<Compile Include="Schema\JsonSchemaResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
+ <Compile Include="Serialization\JsonSerializerProxy.cs" />
+ <Compile Include="Serialization\JsonSerializerReader.cs" />
+ <Compile Include="Serialization\JsonSerializerWriter.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
+ <Compile Include="Utilities\BidirectionalDictionary.cs" />
<Compile Include="Utilities\ConvertUtils.cs" />
<Compile Include="Utilities\CollectionWrapper.cs" />
<Compile Include="Utilities\DateTimeUtils.cs" />
@@ -137,12 +145,12 @@
<Compile Include="JsonToken.cs" />
<Compile Include="JsonWriter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="StringBuffer.cs" />
<Compile Include="Utilities\CollectionUtils.cs" />
<Compile Include="Utilities\ListWrapper.cs" />
<Compile Include="Utilities\MathUtils.cs" />
<Compile Include="Utilities\MiscellaneousUtils.cs" />
<Compile Include="Utilities\ReflectionUtils.cs" />
+ <Compile Include="Utilities\StringBuffer.cs" />
<Compile Include="Utilities\StringUtils.cs" />
<Compile Include="Utilities\ValidationUtils.cs" />
</ItemGroup>
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
index d2ec8c6..28b6718 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
@@ -50,6 +50,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverter.cs" />
+ <Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
<Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
@@ -98,13 +99,19 @@
<Compile Include="MissingMemberHandling.cs" />
<Compile Include="NullValueHandling.cs" />
<Compile Include="ObjectCreationHandling.cs" />
+ <Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
<Compile Include="Serialization\DefaultMappingResolver.cs" />
+ <Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="Serialization\IMappingResolver.cs" />
- <Compile Include="StringBuffer.cs" />
+ <Compile Include="Serialization\IReferenceResolver.cs" />
+ <Compile Include="Serialization\JsonSerializerProxy.cs" />
+ <Compile Include="Serialization\JsonSerializerReader.cs" />
+ <Compile Include="Serialization\JsonSerializerWriter.cs" />
+ <Compile Include="Utilities\BidirectionalDictionary.cs" />
<Compile Include="Utilities\CollectionUtils.cs" />
<Compile Include="Utilities\CollectionWrapper.cs" />
<Compile Include="Utilities\ConvertUtils.cs" />
@@ -118,6 +125,7 @@
<Compile Include="Utilities\MathUtils.cs" />
<Compile Include="Utilities\MiscellaneousUtils.cs" />
<Compile Include="Utilities\ReflectionUtils.cs" />
+ <Compile Include="Utilities\StringBuffer.cs" />
<Compile Include="Utilities\StringUtils.cs" />
<Compile Include="Utilities\ValidationUtils.cs" />
<Compile Include="Schema\Extensions.cs" />
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index 5bd4a07..1ff9fe9 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -84,7 +84,10 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverter.cs" />
+ <Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
+ <Compile Include="Serialization\DefaultReferenceResolver.cs" />
+ <Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="IJsonLineInfo.cs" />
<Compile Include="JsonArrayAttribute.cs" />
<Compile Include="JsonContainerAttribute.cs" />
@@ -133,6 +136,7 @@
<Compile Include="Schema\JsonSchemaModelBuilder.cs" />
<Compile Include="Schema\JsonSchemaNodeCollection.cs" />
<Compile Include="Schema\JsonSchemaNode.cs" />
+ <Compile Include="Schema\JsonSchemaResolver.cs" />
<Compile Include="Schema\JsonSchemaWriter.cs" />
<Compile Include="Schema\UndefinedSchemaIdHandling.cs" />
<Compile Include="Schema\ValidationEventArgs.cs" />
@@ -149,10 +153,14 @@
<Compile Include="Schema\JsonSchemaBuilder.cs" />
<Compile Include="Schema\JsonSchemaConstants.cs" />
<Compile Include="Schema\JsonSchemaGenerator.cs" />
- <Compile Include="Schema\JsonSchemaResolver.cs" />
+ <Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
+ <Compile Include="Serialization\JsonSerializerProxy.cs" />
+ <Compile Include="Serialization\JsonSerializerReader.cs" />
+ <Compile Include="Serialization\JsonSerializerWriter.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
+ <Compile Include="Utilities\BidirectionalDictionary.cs" />
<Compile Include="Utilities\ConvertUtils.cs" />
<Compile Include="Utilities\CollectionWrapper.cs" />
<Compile Include="Utilities\DateTimeUtils.cs" />
@@ -164,7 +172,7 @@
<Compile Include="JsonToken.cs" />
<Compile Include="JsonWriter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="StringBuffer.cs" />
+ <Compile Include="Utilities\StringBuffer.cs" />
<Compile Include="Utilities\CollectionUtils.cs" />
<Compile Include="Utilities\ListWrapper.cs" />
<Compile Include="Utilities\MathUtils.cs" />
diff --git a/Src/Newtonsoft.Json/PreserveReferencesHandling.cs b/Src/Newtonsoft.Json/PreserveReferencesHandling.cs
new file mode 100644
index 0000000..afc55cc
--- /dev/null
+++ b/Src/Newtonsoft.Json/PreserveReferencesHandling.cs
@@ -0,0 +1,40 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ [Flags]
+ public enum PreserveReferencesHandling
+ {
+ None = 0,
+ Objects = 1,
+ Arrays = 2,
+ All = Objects | Arrays
+ }
+}
diff --git a/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs b/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs
index 878f629..38bc2a6 100644
--- a/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs
+++ b/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.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.Linq;
using System.Reflection;
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs
index ebf8b3f..f1b5599 100644
--- a/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/DefaultMappingResolver.cs
@@ -120,6 +120,8 @@ namespace Newtonsoft.Json.Serialization
protected virtual JsonMemberMapping CreateMemberMapping(MemberSerialization memberSerialization, MemberInfo member)
{
+ JsonObjectAttribute jsonObjectAttribute = JsonTypeReflector.GetJsonContainerAttribute(member.DeclaringType) as JsonObjectAttribute;
+
#if !PocketPC
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType);
@@ -174,8 +176,14 @@ namespace Newtonsoft.Json.Serialization
NullValueHandling? nullValueHandling = (propertyAttribute != null) ? propertyAttribute._nullValueHandling : null;
DefaultValueHandling? defaultValueHandling = (propertyAttribute != null) ? propertyAttribute._defaultValueHandling : null;
ReferenceLoopHandling? referenceLoopHandling = (propertyAttribute != null) ? propertyAttribute._referenceLoopHandling : null;
+
+ bool isReference;
+ if (jsonObjectAttribute != null)
+ isReference = jsonObjectAttribute.IsReference;
+ else
+ isReference = false;
- return new JsonMemberMapping(resolvedMappedName, member, ignored, readable, writable, memberConverter, defaultValue, required, nullValueHandling, defaultValueHandling, referenceLoopHandling);
+ return new JsonMemberMapping(resolvedMappedName, member, ignored, readable, writable, memberConverter, defaultValue, required, isReference, nullValueHandling, defaultValueHandling, referenceLoopHandling);
}
protected virtual string ResolveMappingName(string mappedName)
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
new file mode 100644
index 0000000..812278f
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
@@ -0,0 +1,82 @@
+#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.Linq;
+using System.Text;
+using Newtonsoft.Json.Utilities;
+using System.Globalization;
+
+namespace Newtonsoft.Json.Serialization
+{
+ internal class DefaultReferenceResolver : IReferenceResolver
+ {
+ private int _referenceCount;
+ private BidirectionalDictionary<string, object> _mappings;
+
+ private BidirectionalDictionary<string, object> Mappings
+ {
+ get
+ {
+ if (_mappings == null)
+ _mappings = new BidirectionalDictionary<string, object>();
+
+ return _mappings;
+ }
+ }
+
+ public object ResolveObject(string reference)
+ {
+ object value;
+ Mappings.TryGetByFirst(reference, out value);
+ return value;
+ }
+
+ public string ResolveReference(object value)
+ {
+ string reference;
+ if (!Mappings.TryGetBySecond(value, out reference))
+ {
+ _referenceCount++;
+ reference = _referenceCount.ToString(CultureInfo.InvariantCulture);
+ Mappings.Add(reference, value);
+ }
+
+ return reference;
+ }
+
+ public void AddObjectReference(string reference, object value)
+ {
+ Mappings.Add(reference, value);
+ }
+
+ public bool HasObjectReference(object value)
+ {
+ string reference;
+ return Mappings.TryGetBySecond(value, out reference);
+ }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Serialization/IReferenceResolver.cs b/Src/Newtonsoft.Json/Serialization/IReferenceResolver.cs
new file mode 100644
index 0000000..81bf8df
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/IReferenceResolver.cs
@@ -0,0 +1,35 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+namespace Newtonsoft.Json.Serialization
+{
+ public interface IReferenceResolver
+ {
+ object ResolveObject(string reference);
+ string ResolveReference(object value);
+ bool HasObjectReference(object value);
+ void AddObjectReference(string reference, object value);
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonMemberMapping.cs b/Src/Newtonsoft.Json/Serialization/JsonMemberMapping.cs
index a0c6e49..221d068 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonMemberMapping.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonMemberMapping.cs
@@ -40,11 +40,12 @@ namespace Newtonsoft.Json.Serialization
private readonly JsonConverter _memberConverter;
private readonly object _defaultValue;
private readonly bool _required;
+ private readonly bool _isReference;
private readonly NullValueHandling? _nullValueHandling;
private readonly DefaultValueHandling? _defaultValueHandling;
private readonly ReferenceLoopHandling? _referenceLoopHandling;
- public JsonMemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter, object defaultValue, bool required, NullValueHandling? nullValueHandling, DefaultValueHandling? defaultValueHandling, ReferenceLoopHandling? referenceLoopHandling)
+ public JsonMemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter, object defaultValue, bool required, bool isReference, NullValueHandling? nullValueHandling, DefaultValueHandling? defaultValueHandling, ReferenceLoopHandling? referenceLoopHandling)
{
_mappingName = mappingName;
_member = member;
@@ -54,6 +55,7 @@ namespace Newtonsoft.Json.Serialization
_memberConverter = memberConverter;
_defaultValue = defaultValue;
_required = required;
+ _isReference = isReference;
_nullValueHandling = nullValueHandling;
_defaultValueHandling = defaultValueHandling;
_referenceLoopHandling = referenceLoopHandling;
@@ -92,11 +94,16 @@ namespace Newtonsoft.Json.Serialization
public object DefaultValue
{
get { return _defaultValue; }
- }
+ }
public bool Required
{
- get { return _required; }
+ get { return _required; }
+ }
+
+ public bool IsReference
+ {
+ get { return _isReference; }
}
public NullValueHandling? NullValueHandling
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs
new file mode 100644
index 0000000..dae4745
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs
@@ -0,0 +1,130 @@
+#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 Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Serialization
+{
+ internal class JsonSerializerProxy : JsonSerializer
+ {
+ private readonly JsonSerializerReader _serializerReader;
+ private readonly JsonSerializerWriter _serializerWriter;
+ private readonly JsonSerializer _serializer;
+
+ public override IReferenceResolver ReferenceResolver
+ {
+ get { return _serializer.ReferenceResolver; }
+ set { _serializer.ReferenceResolver = value; }
+ }
+
+ public override JsonConverterCollection Converters
+ {
+ get { return _serializer.Converters; }
+ }
+
+ public override DefaultValueHandling DefaultValueHandling
+ {
+ get { return _serializer.DefaultValueHandling; }
+ set { _serializer.DefaultValueHandling = value; }
+ }
+
+ public override IMappingResolver MappingResolver
+ {
+ get { return _serializer.MappingResolver; }
+ set { _serializer.MappingResolver = value; }
+ }
+
+ public override MissingMemberHandling MissingMemberHandling
+ {
+ get { return _serializer.MissingMemberHandling; }
+ set { _serializer.MissingMemberHandling = value; }
+ }
+
+ public override NullValueHandling NullValueHandling
+ {
+ get { return _serializer.NullValueHandling; }
+ set { _serializer.NullValueHandling = value; }
+ }
+
+ public override ObjectCreationHandling ObjectCreationHandling
+ {
+ get { return _serializer.ObjectCreationHandling; }
+ set { _serializer.ObjectCreationHandling = value; }
+ }
+
+ public override ReferenceLoopHandling ReferenceLoopHandling
+ {
+ get { return _serializer.ReferenceLoopHandling; }
+ set { _serializer.ReferenceLoopHandling = value; }
+ }
+
+ public override PreserveReferencesHandling PreserveReferencesHandling
+ {
+ get { return _serializer.PreserveReferencesHandling; }
+ set { _serializer.PreserveReferencesHandling = value; }
+ }
+
+ public JsonSerializerProxy(JsonSerializerReader serializerReader)
+ {
+ ValidationUtils.ArgumentNotNull(serializerReader, "serializerReader");
+
+ _serializerReader = serializerReader;
+ _serializer = serializerReader._serializer;
+ }
+
+ public JsonSerializerProxy(JsonSerializerWriter serializerWriter)
+ {
+ ValidationUtils.ArgumentNotNull(serializerWriter, "serializerWriter");
+
+ _serializerWriter = serializerWriter;
+ _serializer = serializerWriter._serializer;
+ }
+
+ internal override object DeserializeInternal(JsonReader reader, Type objectType)
+ {
+ if (_serializerReader != null)
+ return _serializerReader.Deserialize(reader, objectType);
+ else
+ return _serializer.Deserialize(reader, objectType);
+ }
+
+ internal override void PopulateInternal(JsonReader reader, object target)
+ {
+ if (_serializerReader != null)
+ _serializerReader.Populate(reader, target);
+ else
+ _serializer.Populate(reader, target);
+ }
+
+ internal override void SerializeInternal(JsonWriter jsonWriter, object value)
+ {
+ if (_serializerWriter != null)
+ _serializerWriter.Serialize(jsonWriter, value);
+ else
+ _serializer.Serialize(jsonWriter, value);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs
new file mode 100644
index 0000000..c507761
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerReader.cs
@@ -0,0 +1,615 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Serialization
+{
+ internal class JsonSerializerReader
+ {
+ internal readonly JsonSerializer _serializer;
+ private JsonSerializerProxy _internalSerializer;
+
+ public JsonSerializerReader(JsonSerializer serializer)
+ {
+ ValidationUtils.ArgumentNotNull(serializer, "serializer");
+
+ _serializer = serializer;
+ }
+
+ public void Populate(JsonReader reader, object target)
+ {
+ ValidationUtils.ArgumentNotNull(target, "target");
+
+ Type objectType = target.GetType();
+
+ if (reader.TokenType == JsonToken.None)
+ reader.Read();
+
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ PopulateList(CollectionUtils.CreateCollectionWrapper(target), ReflectionUtils.GetCollectionItemType(objectType), reader, null);
+ }
+ else if (reader.TokenType == JsonToken.StartObject)
+ {
+ if (!reader.Read())
+ throw new JsonSerializationException("Unexpected end when deserializing object.");
+
+ if (CollectionUtils.IsDictionaryType(objectType))
+ PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader);
+ else
+ PopulateObject(target, reader, objectType);
+ }
+ }
+
+ public object Deserialize(JsonReader reader, Type objectType)
+ {
+ if (reader == null)
+ throw new ArgumentNullException("reader");
+
+ if (!reader.Read())
+ return null;
+
+ if (objectType != null)
+ return CreateValue(reader, objectType, null, null);
+ else
+ return CreateJToken(reader);
+ }
+
+ private JsonSerializerProxy GetInternalSerializer()
+ {
+ if (_internalSerializer == null)
+ _internalSerializer = new JsonSerializerProxy(this);
+
+ return _internalSerializer;
+ }
+
+ private JToken CreateJToken(JsonReader reader)
+ {
+ JToken token;
+ using (JTokenWriter writer = new JTokenWriter())
+ {
+ writer.WriteToken(reader);
+ token = writer.Token;
+ }
+
+ return token;
+ }
+
+ private object CreateValue(JsonReader reader, Type objectType, object existingValue, JsonConverter memberConverter)
+ {
+ object value;
+ JsonConverter converter;
+
+ if (memberConverter != null)
+ {
+ return memberConverter.ReadJson(reader, objectType, GetInternalSerializer());
+ }
+ else if (objectType != null && _serializer.HasClassConverter(objectType, out converter))
+ {
+ return converter.ReadJson(reader, objectType, GetInternalSerializer());
+ }
+ else if (objectType != null && _serializer.HasMatchingConverter(objectType, out converter))
+ {
+ return converter.ReadJson(reader, objectType, GetInternalSerializer());
+ }
+ else if (objectType == typeof(JsonRaw))
+ {
+ return JsonRaw.Create(reader);
+ }
+ else
+ {
+ switch (reader.TokenType)
+ {
+ // populate a typed object or generic dictionary/array
+ // depending upon whether an objectType was supplied
+ case JsonToken.StartObject:
+ if (objectType == null)
+ {
+ value = CreateJToken(reader);
+ }
+ else
+ {
+ CheckedRead(reader);
+
+ if (reader.TokenType == JsonToken.PropertyName)
+ {
+ string propertyName = reader.Value.ToString();
+
+ if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
+ {
+ CheckedRead(reader);
+ string id = reader.Value.ToString();
+
+ CheckedRead(reader);
+ return _serializer.ReferenceResolver.ResolveObject(id);
+ }
+ else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)
+ && !CollectionUtils.IsDictionaryType(objectType)
+ && CollectionUtils.IsListType(objectType))
+ {
+ return CreateReferencedList(reader, objectType, existingValue);
+ }
+ }
+
+ if (CollectionUtils.IsDictionaryType(objectType))
+ {
+ if (existingValue == null)
+ value = CreateAndPopulateDictionary(reader, objectType);
+ else
+ value = PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader);
+ }
+ else
+ {
+ if (existingValue == null)
+ value = CreateAndPopulateObject(reader, objectType);
+ else
+ value = PopulateObject(existingValue, reader, objectType);
+ }
+ }
+ break;
+ case JsonToken.StartArray:
+ value = CreateList(reader, objectType, existingValue, null);
+ break;
+ case JsonToken.Integer:
+ case JsonToken.Float:
+ case JsonToken.String:
+ case JsonToken.Boolean:
+ case JsonToken.Date:
+ value = EnsureType(reader.Value, objectType);
+ break;
+ case JsonToken.StartConstructor:
+ case JsonToken.EndConstructor:
+ string constructorName = reader.Value.ToString();
+
+ value = constructorName;
+ break;
+ case JsonToken.Null:
+ case JsonToken.Undefined:
+ if (objectType == typeof(DBNull))
+ value = DBNull.Value;
+ else
+ value = null;
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
+ }
+ }
+
+ return value;
+ }
+
+ private void CheckedRead(JsonReader reader)
+ {
+ if (!reader.Read())
+ throw new JsonSerializationException("Unexpected end when deserializing object.");
+ }
+
+ private object CreateReferencedList(JsonReader reader, Type objectType, object existingValue)
+ {
+ object value;
+
+ CheckedRead(reader);
+ string id = reader.Value.ToString();
+
+ CheckedRead(reader);
+ if (reader.TokenType != JsonToken.PropertyName && reader.Value.ToString() != "value")
+ throw new JsonSerializationException("Error reading referenced list.");
+
+ CheckedRead(reader);
+ if (reader.TokenType != JsonToken.StartArray)
+ throw new JsonSerializationException("Error reading referenced list.");
+
+ value = CreateList(reader, objectType, existingValue, id);
+
+ CheckedRead(reader);
+ return value;
+ }
+
+ private object CreateList(JsonReader reader, Type objectType, object existingValue, string reference)
+ {
+ object value;
+ if (objectType != null)
+ {
+ if (existingValue == null)
+ value = CreateAndPopulateList(reader, objectType, reference);
+ else
+ value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), ReflectionUtils.GetCollectionItemType(objectType), reader, reference);
+ }
+ else
+ {
+ value = CreateJToken(reader);
+ }
+ return value;
+ }
+
+ private object EnsureType(object value, Type targetType)
+ {
+ // do something about null value when the targetType is a valuetype?
+ if (value == null)
+ return null;
+
+ if (targetType == null)
+ return value;
+
+ Type valueType = value.GetType();
+
+ // type of value and type of target don't match
+ // attempt to convert value's type to target's type
+ if (valueType != targetType)
+ {
+ return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ private void SetObjectMember(JsonReader reader, object target, Type targetType, string memberName)
+ {
+ JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(targetType);
+
+ JsonMemberMapping memberMapping;
+ // attempt exact case match first
+ // then try match ignoring case
+ if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
+ {
+ SetMappingValue(memberMapping, reader, target);
+ }
+ else
+ {
+ if (_serializer.MissingMemberHandling == MissingMemberHandling.Error)
+ throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, targetType.Name));
+
+ reader.Skip();
+ }
+ }
+
+ private void SetMappingValue(JsonMemberMapping memberMapping, JsonReader reader, object target)
+ {
+ if (memberMapping.Ignored)
+ {
+ reader.Skip();
+ return;
+ }
+
+ // get the member's underlying type
+ Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
+
+ object currentValue = null;
+ bool useExistingValue = false;
+
+ if ((_serializer.ObjectCreationHandling == ObjectCreationHandling.Auto || _serializer.ObjectCreationHandling == ObjectCreationHandling.Reuse)
+ && (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
+ {
+ currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
+
+ useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericDefinition(memberType, typeof(ReadOnlyCollection<>)));
+ }
+
+ if (!memberMapping.Writable && !useExistingValue)
+ {
+ reader.Skip();
+ return;
+ }
+
+ object value = CreateValue(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(memberMapping.Member, memberType));
+
+ if (!useExistingValue && ShouldSetMappingValue(memberMapping, value))
+ ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
+ }
+
+ private bool ShouldSetMappingValue(JsonMemberMapping memberMapping, object value)
+ {
+ if (memberMapping.NullValueHandling.GetValueOrDefault(_serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
+ return false;
+
+ if (memberMapping.DefaultValueHandling.GetValueOrDefault(_serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, memberMapping.DefaultValue))
+ return false;
+
+ if (!memberMapping.Writable)
+ return false;
+
+ return true;
+ }
+
+ private object CreateAndPopulateDictionary(JsonReader reader, Type objectType)
+ {
+ if (IsTypeGenericDictionaryInterface(objectType))
+ {
+ Type keyType;
+ Type valueType;
+ ReflectionUtils.GetDictionaryKeyValueTypes(objectType, out keyType, out valueType);
+ objectType = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
+ }
+
+ IWrappedDictionary dictionary = CollectionUtils.CreateDictionaryWrapper(Activator.CreateInstance(objectType));
+ PopulateDictionary(dictionary, reader);
+
+ return dictionary.UnderlyingDictionary;
+ }
+
+ private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader)
+ {
+ Type dictionaryType = dictionary.UnderlyingDictionary.GetType();
+ Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryType);
+ Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryType);
+
+ do
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ if (reader.Value is string && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
+ {
+ reader.Read();
+ _serializer.ReferenceResolver.AddObjectReference(reader.Value.ToString(), dictionary.UnderlyingDictionary);
+ }
+ else
+ {
+ object keyValue = EnsureType(reader.Value, dictionaryKeyType);
+ reader.Read();
+
+ dictionary.Add(keyValue, CreateValue(reader, dictionaryValueType, null, null));
+ }
+ break;
+ case JsonToken.EndObject:
+ return dictionary;
+ default:
+ throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ }
+ } while (reader.Read());
+
+ throw new JsonSerializationException("Unexpected end when deserializing object.");
+ }
+
+ private object CreateAndPopulateList(JsonReader reader, Type objectType, string reference)
+ {
+ if (IsTypeGenericCollectionInterface(objectType))
+ {
+ Type itemType = ReflectionUtils.GetCollectionItemType(objectType);
+ objectType = ReflectionUtils.MakeGenericType(typeof(List<>), itemType);
+ }
+
+ return CollectionUtils.CreateAndPopulateList(objectType, (l, isTemporaryListReference) =>
+ {
+ if (reference != null && isTemporaryListReference)
+ throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, objectType));
+
+ PopulateList(l, ReflectionUtils.GetCollectionItemType(objectType), reader, reference);
+ });
+ }
+
+ private IList PopulateList(IList list, Type listItemType, JsonReader reader, string reference)
+ {
+ if (reference != null)
+ _serializer.ReferenceResolver.AddObjectReference(reference, list);
+
+ while (reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.EndArray:
+ return list;
+ case JsonToken.Comment:
+ break;
+ default:
+ object value = CreateValue(reader, listItemType, null, null);
+
+ list.Add(value);
+ break;
+ }
+ }
+
+ throw new JsonSerializationException("Unexpected end when deserializing array.");
+ }
+
+ private bool IsTypeGenericDictionaryInterface(Type type)
+ {
+ if (!type.IsGenericType)
+ return false;
+
+ Type genericDefinition = type.GetGenericTypeDefinition();
+
+ return (genericDefinition == typeof(IDictionary<,>));
+ }
+
+ private bool IsTypeGenericCollectionInterface(Type type)
+ {
+ if (!type.IsGenericType)
+ return false;
+
+ Type genericDefinition = type.GetGenericTypeDefinition();
+
+ return (genericDefinition == typeof(IList<>)
+ || genericDefinition == typeof(ICollection<>)
+ || genericDefinition == typeof(IEnumerable<>));
+ }
+
+ private object CreateAndPopulateObject(JsonReader reader, Type objectType)
+ {
+ object newObject;
+
+ if (objectType.IsInterface || objectType.IsAbstract)
+ throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, objectType));
+
+ if (ReflectionUtils.HasDefaultConstructor(objectType))
+ {
+ newObject = Activator.CreateInstance(objectType);
+
+ PopulateObject(newObject, reader, objectType);
+ return newObject;
+ }
+
+ return CreateObjectFromNonDefaultConstructor(objectType, reader);
+ }
+
+ private object CreateObjectFromNonDefaultConstructor(Type objectType, JsonReader reader)
+ {
+ // object should have a single constructor
+ ConstructorInfo c = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault();
+
+ if (c == null)
+ throw new JsonSerializationException("Could not find a public constructor for type {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
+
+ // create a dictionary to put retrieved values into
+ JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(objectType);
+ IDictionary<JsonMemberMapping, object> mappingValues = memberMappings.ToDictionary(kv => kv, kv => (object)null);
+
+ bool exit = false;
+ do
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string memberName = reader.Value.ToString();
+ if (!reader.Read())
+ throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
+
+ JsonMemberMapping memberMapping;
+ // attempt exact case match first
+ // then try match ignoring case
+ if (memberMappings.TryGetClosestMatchMapping(memberName, out memberMapping))
+ {
+ if (!memberMapping.Ignored)
+ {
+ Type memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
+ mappingValues[memberMapping] = CreateValue(reader, memberType, null, memberMapping.MemberConverter);
+ }
+ }
+ else
+ {
+ if (_serializer.MissingMemberHandling == MissingMemberHandling.Error)
+ throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
+
+ reader.Skip();
+ }
+ break;
+ case JsonToken.EndObject:
+ exit = true;
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ }
+ } while (!exit && reader.Read());
+
+ IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
+ IDictionary<JsonMemberMapping, object> remainingMappingValues = new Dictionary<JsonMemberMapping, object>();
+
+ foreach (KeyValuePair<JsonMemberMapping, object> mappingValue in mappingValues)
+ {
+ ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, mappingValue.Key.MappingName).Key;
+ if (matchingConstructorParameter != null)
+ constructorParameters[matchingConstructorParameter] = mappingValue.Value;
+ else
+ remainingMappingValues.Add(mappingValue);
+ }
+
+ object createdObject = ReflectionUtils.CreateInstance(objectType, constructorParameters.Values.ToArray());
+
+ // go through unused values and set the newly created object's properties
+ foreach (KeyValuePair<JsonMemberMapping, object> remainingMappingValue in remainingMappingValues)
+ {
+ if (ShouldSetMappingValue(remainingMappingValue.Key, remainingMappingValue.Value))
+ ReflectionUtils.SetMemberValue(remainingMappingValue.Key.Member, createdObject, remainingMappingValue.Value);
+ }
+
+ return createdObject;
+ }
+
+ private object PopulateObject(object newObject, JsonReader reader, Type objectType)
+ {
+ JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(objectType);
+ Dictionary<string, bool> requiredMappings =
+ memberMappings.Where(m => m.Required).ToDictionary(m => m.MappingName, m => false);
+
+ do
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string memberName = reader.Value.ToString();
+
+ if (!reader.Read())
+ throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
+
+ if (string.Equals(memberName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
+ {
+ _serializer.ReferenceResolver.AddObjectReference(reader.Value.ToString(), newObject);
+ }
+ else
+ {
+ if (reader.TokenType != JsonToken.Null)
+ SetRequiredMapping(memberName, requiredMappings);
+
+ SetObjectMember(reader, newObject, objectType, memberName);
+ }
+ break;
+ case JsonToken.EndObject:
+ foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
+ {
+ if (!requiredMapping.Value)
+ throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredMapping.Key));
+ }
+ return newObject;
+ default:
+ throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
+ }
+ } while (reader.Read());
+
+ throw new JsonSerializationException("Unexpected end when deserializing object.");
+ }
+
+ private void SetRequiredMapping(string memberName, Dictionary<string, bool> requiredMappings)
+ {
+ // first attempt to find exact case match
+ // then attempt case insensitive match
+ if (requiredMappings.ContainsKey(memberName))
+ {
+ requiredMappings[memberName] = true;
+ }
+ else
+ {
+ foreach (KeyValuePair<string, bool> requiredMapping in requiredMappings)
+ {
+ if (string.Compare(requiredMapping.Key, requiredMapping.Key, StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ requiredMappings[requiredMapping.Key] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs
new file mode 100644
index 0000000..5ece158
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerWriter.cs
@@ -0,0 +1,375 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Serialization
+{
+ internal class JsonSerializerWriter
+ {
+ internal readonly JsonSerializer _serializer;
+ private JsonSerializerProxy _internalSerializer;
+ private List<object> _serializeStack;
+
+ private List<object> SerializeStack
+ {
+ get
+ {
+ if (_serializeStack == null)
+ _serializeStack = new List<object>();
+
+ return _serializeStack;
+ }
+ }
+
+ public JsonSerializerWriter(JsonSerializer serializer)
+ {
+ ValidationUtils.ArgumentNotNull(serializer, "serializer");
+
+ _serializer = serializer;
+ }
+
+ public void Serialize(JsonWriter jsonWriter, object value)
+ {
+ if (jsonWriter == null)
+ throw new ArgumentNullException("jsonWriter");
+
+ if (value is JToken)
+ ((JToken)value).WriteTo(jsonWriter, (_serializer.Converters != null) ? _serializer.Converters.ToArray() : null);
+ else
+ SerializeValue(jsonWriter, value, null);
+ }
+
+ private JsonSerializerProxy GetInternalSerializer()
+ {
+ if (_internalSerializer == null)
+ _internalSerializer = new JsonSerializerProxy(this);
+
+ return _internalSerializer;
+ }
+
+ private void SerializeValue(JsonWriter writer, object value, JsonConverter memberConverter)
+ {
+ JsonConverter converter = memberConverter;
+
+ if (value == null)
+ {
+ writer.WriteNull();
+ }
+ else if (converter != null
+ || _serializer.HasClassConverter(value.GetType(), out converter)
+ || _serializer.HasMatchingConverter(value.GetType(), out converter))
+ {
+ SerializeConvertable(writer, converter, value);
+ }
+ else if (JsonConvert.IsJsonPrimitive(value))
+ {
+ writer.WriteValue(value);
+ }
+ else if (value is IList)
+ {
+ SerializeList(writer, (IList)value);
+ }
+ else if (value is IDictionary)
+ {
+ SerializeDictionary(writer, (IDictionary)value);
+ }
+ else if (value is IEnumerable)
+ {
+ SerializeEnumerable(writer, (IEnumerable)value);
+ }
+ else if (value is JsonRaw)
+ {
+ writer.WriteRawValue(((JsonRaw)value).Content);
+ }
+ else
+ {
+ SerializeObject(writer, value);
+ }
+ }
+
+ private bool ShouldWriteReference(object value)
+ {
+ if (value == null)
+ return false;
+ if (JsonConvert.IsJsonPrimitive(value))
+ return false;
+
+ Type t = value.GetType();
+
+ bool? isReference = IsReference(t);
+
+ if (isReference == null)
+ {
+ if (value is IList)
+ isReference = HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
+ else if (value is IDictionary)
+ isReference = HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
+ else if (value is IEnumerable)
+ isReference = HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
+ else
+ isReference = HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
+ }
+
+ if (!isReference.Value)
+ return false;
+
+ return _serializer.ReferenceResolver.HasObjectReference(value);
+ }
+
+ private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonMemberMapping memberMapping)
+ {
+ MemberInfo member = memberMapping.Member;
+ string propertyName = memberMapping.MappingName;
+ JsonConverter memberConverter = memberMapping.MemberConverter;
+ object defaultValue = memberMapping.DefaultValue;
+
+ if (!ReflectionUtils.IsIndexedProperty(member))
+ {
+ object memberValue = ReflectionUtils.GetMemberValue(member, value);
+
+ if (memberMapping.NullValueHandling.GetValueOrDefault(_serializer.NullValueHandling) == NullValueHandling.Ignore && memberValue == null)
+ return;
+
+ if (memberMapping.DefaultValueHandling.GetValueOrDefault(_serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
+ return;
+
+ if (ShouldWriteReference(memberValue))
+ {
+ writer.WritePropertyName(propertyName ?? member.Name);
+ WriteReference(writer, memberValue);
+ return;
+ }
+
+ if (!CheckForCircularReference(memberValue, memberMapping.ReferenceLoopHandling))
+ return;
+
+ writer.WritePropertyName(propertyName ?? member.Name);
+ SerializeValue(writer, memberValue, memberConverter);
+ }
+ }
+
+ private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling)
+ {
+ if (SerializeStack.IndexOf(value) != -1)
+ {
+ switch (referenceLoopHandling.GetValueOrDefault(_serializer.ReferenceLoopHandling))
+ {
+ case ReferenceLoopHandling.Error:
+ throw new JsonSerializationException("Self referencing loop");
+ case ReferenceLoopHandling.Ignore:
+ return false;
+ case ReferenceLoopHandling.Serialize:
+ return true;
+ default:
+ throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, _serializer.ReferenceLoopHandling));
+ }
+ }
+
+ return true;
+ }
+
+ private void WriteReference(JsonWriter writer, object value)
+ {
+ writer.WriteStartObject();
+ writer.WritePropertyName(JsonTypeReflector.RefPropertyName);
+ writer.WriteValue(_serializer.ReferenceResolver.ResolveReference(value));
+ writer.WriteEndObject();
+ }
+
+ private void SerializeObject(JsonWriter writer, object value)
+ {
+ Type objectType = value.GetType();
+
+#if !SILVERLIGHT && !PocketPC
+ TypeConverter converter = TypeDescriptor.GetConverter(objectType);
+
+ // use the objectType's TypeConverter if it has one and can convert to a string
+ if (converter != null && !(converter is ComponentConverter) && (converter.GetType() != typeof (TypeConverter) || value is Type))
+ {
+ if (converter.CanConvertTo(typeof (string)))
+ {
+ writer.WriteValue(converter.ConvertToInvariantString(value));
+ return;
+ }
+ }
+#else
+ if (value is Guid || value is Type)
+ {
+ writer.WriteValue(value.ToString());
+ return;
+ }
+#endif
+
+
+
+ SerializeStack.Add(value);
+ writer.WriteStartObject();
+
+ bool isReference = IsReference(objectType) ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
+ if (isReference)
+ {
+ writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
+ writer.WriteValue(_serializer.ReferenceResolver.ResolveReference(value));
+ }
+
+ JsonMemberMappingCollection memberMappings = _serializer.GetMemberMappings(objectType);
+
+ foreach (JsonMemberMapping memberMapping in memberMappings)
+ {
+ if (!memberMapping.Ignored && memberMapping.Readable)
+ WriteMemberInfoProperty(writer, value, memberMapping);
+ }
+
+ writer.WriteEndObject();
+ SerializeStack.RemoveAt(SerializeStack.Count - 1);
+ }
+
+ private bool HasFlag(PreserveReferencesHandling value, PreserveReferencesHandling flag)
+ {
+ return ((value & flag) == flag);
+ }
+
+ private bool? IsReference(Type t)
+ {
+ JsonContainerAttribute containerAttribute = JsonTypeReflector.GetJsonContainerAttribute(t);
+ if (containerAttribute == null)
+ return null;
+
+ return containerAttribute._isReference;
+ }
+
+ private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value)
+ {
+ if (ShouldWriteReference(value))
+ {
+ WriteReference(writer, value);
+ }
+ else
+ {
+ if (!CheckForCircularReference(value, null))
+ return;
+
+ SerializeStack.Add(value);
+
+ converter.WriteJson(writer, value, GetInternalSerializer());
+
+ SerializeStack.RemoveAt(SerializeStack.Count - 1);
+ }
+ }
+
+ private void SerializeEnumerable(JsonWriter writer, IEnumerable values)
+ {
+ SerializeList(writer, values.Cast<object>().ToList());
+ }
+
+ private void SerializeList(JsonWriter writer, IList values)
+ {
+ SerializeStack.Add(values);
+
+ bool isReference = IsReference(values.GetType()) ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
+ if (isReference)
+ {
+ writer.WriteStartObject();
+ writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
+ writer.WriteValue(_serializer.ReferenceResolver.ResolveReference(values));
+
+ writer.WritePropertyName("value");
+ }
+
+ writer.WriteStartArray();
+
+ for (int i = 0; i < values.Count; i++)
+ {
+ object value = values[i];
+
+ if (ShouldWriteReference(value))
+ {
+ WriteReference(writer, value);
+ }
+ else
+ {
+ if (!CheckForCircularReference(value, null))
+ continue;
+
+ SerializeValue(writer, value, null);
+ }
+ }
+
+ writer.WriteEndArray();
+
+ if (isReference)
+ {
+ writer.WriteEndObject();
+ }
+
+ SerializeStack.RemoveAt(SerializeStack.Count - 1);
+ }
+
+ private void SerializeDictionary(JsonWriter writer, IDictionary values)
+ {
+ SerializeStack.Add(values);
+ writer.WriteStartObject();
+
+ bool isReference = IsReference(values.GetType()) ?? HasFlag(_serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
+ if (isReference)
+ {
+ writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
+ writer.WriteValue(_serializer.ReferenceResolver.ResolveReference(values));
+ }
+
+ foreach (DictionaryEntry entry in values)
+ {
+ string propertyName = entry.Key.ToString();
+ object value = entry.Value;
+
+ if (ShouldWriteReference(value))
+ {
+ writer.WritePropertyName(propertyName);
+ WriteReference(writer, value);
+ }
+ else
+ {
+ if (!CheckForCircularReference(value, null))
+ continue;
+
+ writer.WritePropertyName(propertyName);
+ SerializeValue(writer, value, null);
+ }
+ }
+
+ writer.WriteEndObject();
+ SerializeStack.RemoveAt(SerializeStack.Count - 1);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
index 7f334f9..5059882 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
@@ -38,6 +38,9 @@ namespace Newtonsoft.Json.Serialization
{
internal static class JsonTypeReflector
{
+ public const string IdPropertyName = "$id";
+ public const string RefPropertyName = "$ref";
+
private static readonly Dictionary<ICustomAttributeProvider, Type> ConverterTypeCache = new Dictionary<ICustomAttributeProvider, Type>();
private static readonly Dictionary<Type, Type> AssociatedMetadataTypesCache = new Dictionary<Type, Type>();
diff --git a/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs b/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs
new file mode 100644
index 0000000..f651f94
--- /dev/null
+++ b/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs
@@ -0,0 +1,58 @@
+#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.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal class BidirectionalDictionary<TFirst, TSecond>
+ {
+ private readonly IDictionary<TFirst, TSecond> _firstToSecond = new Dictionary<TFirst, TSecond>();
+ private readonly IDictionary<TSecond, TFirst> _secondToFirst = new Dictionary<TSecond, TFirst>();
+
+ public void Add(TFirst first, TSecond second)
+ {
+ if (_firstToSecond.ContainsKey(first) || _secondToFirst.ContainsKey(second))
+ {
+ throw new ArgumentException("Duplicate first or second");
+ }
+ _firstToSecond.Add(first, second);
+ _secondToFirst.Add(second, first);
+ }
+
+ public bool TryGetByFirst(TFirst first, out TSecond second)
+ {
+ return _firstToSecond.TryGetValue(first, out second);
+ }
+
+ public bool TryGetBySecond(TSecond second, out TFirst first)
+ {
+ return _secondToFirst.TryGetValue(second, out first);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs
index cace4bb..15feeb8 100644
--- a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs
@@ -484,7 +484,7 @@ namespace Newtonsoft.Json.Utilities
}
}
- public static IList CreateAndPopulateList(Type listType, Action<IList> populateList)
+ public static IList CreateAndPopulateList(Type listType, Action<IList, bool> populateList)
{
ValidationUtils.ArgumentNotNull(listType, "listType");
ValidationUtils.ArgumentNotNull(populateList, "populateList");
@@ -549,7 +549,7 @@ namespace Newtonsoft.Json.Utilities
if (list == null)
throw new Exception("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
- populateList(list);
+ populateList(list, isReadOnlyOrFixedSize);
// create readonly and fixed sized collections using the temporary list
if (isReadOnlyOrFixedSize)
diff --git a/Src/Newtonsoft.Json/StringBuffer.cs b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs
index 574af4a..b458f39 100644
--- a/Src/Newtonsoft.Json/StringBuffer.cs
+++ b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs
@@ -25,7 +25,7 @@
using System;
-namespace Newtonsoft.Json
+namespace Newtonsoft.Json.Utilities
{
/// <summary>
/// Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer.