-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:
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user