-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
This commit is contained in:
JamesNK
2009-05-13 10:15:41 +00:00
parent 3b26adfdd1
commit f0c5be266b
41 changed files with 2467 additions and 717 deletions
+736 -2
View File
@@ -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);
}
}
}
@@ -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);
@@ -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);
@@ -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" />
@@ -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" />
@@ -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" />
+6 -1
View File
@@ -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(@"""", @"""""") + @"""";
}
@@ -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);
@@ -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; }
}
}
@@ -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)
@@ -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);
}
}
}
@@ -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();
}
@@ -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)
@@ -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)
@@ -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)
@@ -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))
@@ -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>
+4 -2
View File
@@ -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.
+97 -659
View File
@@ -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>
@@ -201,27 +243,6 @@ namespace Newtonsoft.Json
return Deserialize(reader, null);
}
/// <summary>
/// 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="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(JsonReader 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);
}
/// <summary>
/// Deserializes the Json structure contained by the specified <see cref="StringReader"/>
/// into an instance of the specified type.
@@ -234,463 +255,26 @@ namespace Newtonsoft.Json
return Deserialize(new JsonTextReader(reader), objectType);
}
private JToken CreateJToken(JsonReader reader)
/// <summary>
/// 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="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(JsonReader reader, Type objectType)
{
JToken token;
using (JTokenWriter writer = new JTokenWriter())
{
writer.WriteToken(reader);
token = writer.Token;
}
return token;
return DeserializeInternal(reader, objectType);
}
private bool HasClassConverter(Type objectType, out JsonConverter converter)
internal virtual object DeserializeInternal(JsonReader reader, Type objectType)
{
if (objectType == null)
throw new ArgumentNullException("objectType");
ValidationUtils.ArgumentNotNull(reader, "reader");
converter = JsonTypeReflector.GetConverter(objectType, objectType);
return (converter != null);
JsonSerializerReader serializerReader = new JsonSerializerReader(this);
return serializerReader.Deserialize(reader, objectType);
}
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)
{
// 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;
}
private object PopulateObject(object newObject, 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);
}
}
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;
}
}
}
}
#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");
if (value is JToken)
((JToken)value).WriteTo(jsonWriter, (_converters != null) ? _converters.ToArray() : null);
else
SerializeValue(jsonWriter, value, null);
SerializeInternal(jsonWriter, value);
}
private void SerializeValue(JsonWriter writer, object value, JsonConverter memberConverter)
internal virtual void SerializeInternal(JsonWriter jsonWriter, object value)
{
JsonConverter converter;
ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
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);
}
JsonSerializerWriter serializerWriter = new JsonSerializerWriter(this);
serializerWriter.Serialize(jsonWriter, value);
}
private bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
internal bool HasClassConverter(Type objectType, out JsonConverter converter)
{
if (objectType == null)
throw new ArgumentNullException("objectType");
converter = JsonTypeReflector.GetConverter(objectType, objectType);
return (converter != null);
}
internal JsonMemberMappingCollection GetMemberMappings(Type objectType)
{
ValidationUtils.ArgumentNotNull(objectType, "objectType");
if (_mappingResolver != null)
return _mappingResolver.ResolveMappings(objectType);
return DefaultMappingResolver.Instance.ResolveMappings(objectType);
}
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
}
}
@@ -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>();
}
}
+1 -13
View File
@@ -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.
+7 -1
View File
@@ -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));
+9 -2
View File
@@ -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");
+8 -4
View File
@@ -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)
+1 -1
View File
@@ -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);
}
@@ -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>
@@ -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" />
+10 -2
View File
@@ -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" />
@@ -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
}
}
@@ -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;
@@ -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)
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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
@@ -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);
}
}
}
@@ -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;
}
}
}
}
}
}
@@ -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);
}
}
}
@@ -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>();
@@ -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);
}
}
}
@@ -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)
@@ -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.