-Added ObjectCreationHandling to JsonPropertyAttribute

-Added IValueProvider, ReflectionValueProvider, DynamicValueProvider
-Added Dynamic.snk
-Added Required enum with options Default, AllowNull and Always
-Added serialization event support to Silverlight version
-Added Converter to JsonProperty for JsonConverter
-Changed IsRequired to Required enum
-Changed schema generator to allow for Required enum options
-Changed Silverlight project version to Silverlight 3
-Improved error message when JSON array encountered for object and vice-versa when deserializing
-Improved error message for converting types when deserializing
-Improved error message from getting and setting properties when serializing and deserializing
-Fixed empty string being converted to null when deserializing
-Removed dependency on Entity Framework and LINQ to SQL assemblies
This commit is contained in:
JamesNK
2009-11-02 08:21:02 +00:00
parent b4b3905714
commit 2a63ea24e3
51 changed files with 1466 additions and 260 deletions
+6 -1
View File
@@ -60,7 +60,12 @@
JSON array populated with the IEnumerable values. Placing the JsonPropertyAttribute overrides this
behavor and forces the serializer to serialize the class's fields and properties.</p>
<h5>JsonPropertyAttribute</h5>
<p>Allows the name of the serialized member to be customized. The attribute also indicates that a member should be serialized when member serialization is set to opt-in.</p>
<p>JsonPropertyAttribute has a number of uses:</p>
<ul>
<li>By default the JSON property will have the same name as the .NET property. This attribute allows the name to be customized.</li>
<li>Indicates that a property should be serialized when member serialization is set to opt-in.</li>
<li>Includes non-public properties in serialization and deserialization.</li>
</ul>
<h5>JsonIgnoreAttribute</h5>
<p>Excludes a field or property from serialization.</p>
<h5>JsonConverterAttribute</h5>
@@ -12,6 +12,11 @@
<AssemblyName>Newtonsoft.Json.Tests.Silverlight</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<SilverlightApplication>false</SilverlightApplication>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -195,7 +200,7 @@
<Name>Newtonsoft.Json.Silverlight</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v3.0\Microsoft.Silverlight.CSharp.targets" Condition="" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
@@ -113,6 +113,12 @@
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
<Compile Include="Linq\JPathTests.cs" />
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
<Compile Include="Serialization\ContractResolverTests.cs" />
<Compile Include="Serialization\DefaultValueHandlingTests.cs" />
<Compile Include="Serialization\NullValueHandlingTests.cs" />
<Compile Include="TestObjects\Car.cs" />
<Compile Include="TestObjects\Computer.cs" />
<Compile Include="TestObjects\Movie.cs" />
<Compile Include="TestObjects\PersonError.cs" />
<Compile Include="TestObjects\PrivateConstructorTestClass.cs" />
<Compile Include="TestObjects\PrivateConstructorWithPublicParametizedConstructorTestClass.cs" />
@@ -21,6 +21,7 @@ namespace Newtonsoft.Json.Tests
public class PerformanceTests : TestFixtureBase
{
private int Iterations = 100;
//private int Iterations = 5000;
public enum SerializeMethod
{
@@ -59,7 +59,7 @@ namespace Newtonsoft.Json.Tests.Schema
}
}", json);
}
#if !PocketPC
[Test]
public void Generate_DefaultValueAttributeTestClass()
@@ -179,7 +179,7 @@ namespace Newtonsoft.Json.Tests.Schema
Assert.AreEqual(JsonSchemaType.String, schema.Properties["FirstName"].Type);
Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["MiddleName"].Type);
Assert.AreEqual(JsonSchemaType.String, schema.Properties["LastName"].Type);
Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["LastName"].Type);
Assert.AreEqual(JsonSchemaType.String, schema.Properties["BirthDate"].Type);
}
@@ -264,7 +264,7 @@ namespace Newtonsoft.Json.Tests.Schema
JsonSchema schema = generator.Generate(typeof(CircularReferenceWithIdClass));
Assert.AreEqual(JsonSchemaType.String, schema.Properties["Name"].Type);
Assert.AreEqual(JsonSchemaType.String | JsonSchemaType.Null, schema.Properties["Name"].Type);
Assert.AreEqual("MyExplicitId", schema.Id);
Assert.AreEqual(JsonSchemaType.Object, schema.Properties["Child"].Type);
Assert.AreEqual(schema, schema.Properties["Child"]);
@@ -287,7 +287,7 @@ namespace Newtonsoft.Json.Tests.Schema
{
IList<JsonProperty> properties = base.CreateProperties(contract);
JsonPropertyCollection c = new JsonPropertyCollection();
JsonPropertyCollection c = new JsonPropertyCollection(contract);
CollectionUtils.AddRange(c, (IEnumerable)properties.Where(m => m.PropertyName != "Root"));
return c;
@@ -116,7 +116,9 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("Private!", ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("_privateString", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
Assert.AreEqual("Internal!", ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("_internalString", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
Assert.AreEqual(-2, ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("i", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
// readonly
Assert.AreEqual(0, ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("i", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
}
[Test]
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Tests.Serialization
{
public class DynamicContractResolver : DefaultContractResolver
{
private readonly char _startingWithChar;
public DynamicContractResolver(char startingWithChar)
{
_startingWithChar = startingWithChar;
}
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
{
IList<JsonProperty> properties = base.CreateProperties(contract);
// only serializer properties that start with the specified character
properties =
properties.Where(p => p.PropertyName.StartsWith(_startingWithChar.ToString())).ToList();
return properties;
}
}
public class Book
{
public string BookName { get; set; }
public decimal BookPrice { get; set; }
public string AuthorName { get; set; }
public int AuthorAge { get; set; }
public string AuthorCountry { get; set; }
}
public class ContractResolverTests : TestFixtureBase
{
[Test]
public void SingleTypeWithMultipleContractResolvers()
{
Book book = new Book
{
BookName = "The Gathering Storm",
BookPrice = 16.19m,
AuthorName = "Brandon Sanderson",
AuthorAge = 34,
AuthorCountry = "United States of America"
};
string startingWithA = JsonConvert.SerializeObject(book, Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('A') });
// {
// "AuthorName": "Brandon Sanderson",
// "AuthorAge": 34,
// "AuthorCountry": "United States of America"
// }
string startingWithB = JsonConvert.SerializeObject(book, Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('B') });
// {
// "BookName": "The Gathering Storm",
// "BookPrice": 16.19
// }
Assert.AreEqual(@"{
""AuthorName"": ""Brandon Sanderson"",
""AuthorAge"": 34,
""AuthorCountry"": ""United States of America""
}", startingWithA);
Assert.AreEqual(@"{
""BookName"": ""The Gathering Storm"",
""BookPrice"": 16.19
}", startingWithB);
}
}
}
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Serialization
{
public class DefaultValueHandlingTests : TestFixtureBase
{
[Test]
public void SerializeInvoice()
{
Invoice invoice = new Invoice
{
Company = "Acme Ltd.",
Amount = 50.0m,
Paid = false,
FollowUpDays = 30,
FollowUpEmailAddress = string.Empty,
PaidDate = null
};
string included = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { });
// {
// "Company": "Acme Ltd.",
// "Amount": 50.0,
// "Paid": false,
// "PaidDate": null,
// "FollowUpDays": 30,
// "FollowUpEmailAddress": ""
// }
string ignored = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
// {
// "Company": "Acme Ltd.",
// "Amount": 50.0
// }
Console.WriteLine(included);
Console.WriteLine(ignored);
}
[Test]
public void DefaultValueAttributeTest()
{
string json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass(),
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{""TestField1"":0,""TestProperty1"":null}", json);
json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = int.MinValue, TestProperty1 = "NotDefault" },
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{""TestField1"":-2147483648,""TestProperty1"":""NotDefault""}", json);
json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = 21, TestProperty1 = "NotDefault" },
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{""TestProperty1"":""NotDefault""}", json);
json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = 21, TestProperty1 = "TestProperty1Value" },
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{}", json);
}
}
}
@@ -45,6 +45,7 @@ using System.Runtime.Serialization.Json;
using Newtonsoft.Json.Tests.TestObjects;
using System.Runtime.Serialization;
using System.Globalization;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Tests.Serialization
{
@@ -60,6 +61,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Store deserializedStore = (Store)JsonConvert.DeserializeObject(jsonText, typeof(Store));
Assert.AreEqual(store.Establised, deserializedStore.Establised);
Assert.AreEqual(store.product.Count, deserializedStore.product.Count);
Console.WriteLine(jsonText);
}
@@ -509,31 +511,6 @@ keyword such as type of business.""
CollectionAssert.AreEqual(collection, collectionNew);
}
[Test]
public void NullValueHandlingSerialization()
{
Store s1 = new Store();
JsonSerializer jsonSerializer = new JsonSerializer();
jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
StringWriter sw = new StringWriter();
jsonSerializer.Serialize(sw, s1);
//JsonConvert.ConvertDateTimeToJavaScriptTicks(s1.Establised.DateTime)
Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000+0000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0}]}", sw.GetStringBuilder().ToString());
Store s2 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader("{}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s2.Escape);
Store s3 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Escape"":null}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s3.Escape);
Store s4 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Color"":2,""Establised"":""\/Date(1264071600000+1300)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949485690000+1300)\/"",""Price"":0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946638000000)\/"",""Price"":0.0}]}")), typeof(Store));
Assert.AreEqual(s1.Establised, s3.Establised);
}
[Test]
public void SerializeObject()
{
@@ -860,49 +837,6 @@ keyword such as type of business.""
Assert.AreEqual(@"{""Id"":0}", json);
}
[Test]
public void DefaultValueAttributeTest()
{
string json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass(),
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{""TestField1"":0,""TestProperty1"":null}", json);
json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = int.MinValue, TestProperty1 = "NotDefault" },
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{""TestField1"":-2147483648,""TestProperty1"":""NotDefault""}", json);
json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = 21, TestProperty1 = "NotDefault" },
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{""TestProperty1"":""NotDefault""}", json);
json = JsonConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = 21, TestProperty1 = "TestProperty1Value" },
Formatting.None, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Assert.AreEqual(@"{}", json);
}
[Test]
public void SerializeInvoice()
{
Invoice invoice = new Invoice
{
Company = "Acme Ltd.",
Amount = 50.0m,
Paid = false
};
string json = JsonConvert.SerializeObject(invoice);
Console.WriteLine(json);
// {"Company":"Acme Ltd.","Amount":50.0,"Paid":false,"PaidDate":null}
json = JsonConvert.SerializeObject(invoice,
Formatting.None,
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Console.WriteLine(json);
// {"Company":"Acme Ltd.","Amount":50.0}
}
[Test]
public void DeserializeNullable()
{
@@ -1024,7 +958,7 @@ keyword such as type of business.""
public void RequiredMembersClassWithNullValues()
{
string json = @"{
""FirstName"": null,
""FirstName"": ""I can't be null bro!"",
""MiddleName"": null,
""LastName"": null,
""BirthDate"": ""\/Date(977309755000)\/""
@@ -1032,7 +966,23 @@ keyword such as type of business.""
RequiredMembersClass c = JsonConvert.DeserializeObject<RequiredMembersClass>(json);
Assert.AreEqual(null, c.FirstName);
Assert.AreEqual("I can't be null bro!", c.FirstName);
Assert.AreEqual(null, c.MiddleName);
Assert.AreEqual(null, c.LastName);
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Required property 'FirstName' expects a value but got null.")]
public void RequiredMembersClassNullRequiredValueProperty()
{
string json = @"{
""FirstName"": null,
""MiddleName"": null,
""LastName"": null,
""BirthDate"": ""\/Date(977309755000)\/""
}";
JsonConvert.DeserializeObject<RequiredMembersClass>(json);
}
[Test]
@@ -1815,20 +1765,151 @@ keyword such as type of business.""
}
[Test]
public void DeserializeNullableListWithNullss()
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot deserialize JSON array into type 'Newtonsoft.Json.Tests.TestObjects.Person'.")]
public void CannotDeserializeArrayIntoObject()
{
//JavaScriptSerializer s = new JavaScriptSerializer();
//s.Deserialize<List<decimal?>>("[ 3.3, null, 1.1 ] ");
string json = @"[]";
//DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(List<decimal?>));
//s.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes("[ 3.3, null, 1.1 ] ")));
JsonConvert.DeserializeObject<Person>(json);
}
List<decimal?> l = JsonConvert.DeserializeObject<List<decimal?>>("[ 3.3, null, 1.1 ] ");
Assert.AreEqual(3, l.Count);
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]'.")]
public void CannotDeserializeObjectIntoArray()
{
string json = @"{}";
Assert.AreEqual(3.3m, l[0]);
Assert.AreEqual(null, l[1]);
Assert.AreEqual(1.1m, l[2]);
JsonConvert.DeserializeObject<List<Person>>(json);
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot populate JSON array onto type 'Newtonsoft.Json.Tests.TestObjects.Person'.")]
public void CannotPopulateArrayIntoObject()
{
string json = @"[]";
JsonConvert.PopulateObject(json, new Person());
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot populate JSON object onto type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]'.")]
public void CannotPopulateObjectIntoArray()
{
string json = @"{}";
JsonConvert.PopulateObject(json, new List<Person>());
}
[Test]
public void DeserializeEmptyString()
{
string json = @"{""Name"":""""}";
Person p = JsonConvert.DeserializeObject<Person>(json);
Assert.AreEqual("", p.Name);
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Error getting value from 'ReadTimeout' on 'System.IO.MemoryStream'.")]
public void SerializePropertyGetError()
{
JsonConvert.SerializeObject(new MemoryStream());
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Error setting value to 'ReadTimeout' on 'System.IO.MemoryStream'.")]
public void DeserializePropertySetError()
{
JsonConvert.DeserializeObject<MemoryStream>("{ReadTimeout:0}");
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Error converting value """" to type 'System.Int32'.")]
public void DeserializeEnsureTypeEmptyStringToIntError()
{
JsonConvert.DeserializeObject<MemoryStream>("{ReadTimeout:''}");
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Error converting value {null} to type 'System.Int32'.")]
public void DeserializeEnsureTypeNullToIntError()
{
JsonConvert.DeserializeObject<MemoryStream>("{ReadTimeout:null}");
}
[Test]
public void SerializeGenericListOfStrings()
{
List<String> strings = new List<String>();
strings.Add("str_1");
strings.Add("str_2");
strings.Add("str_3");
string json = JsonConvert.SerializeObject(strings);
Assert.AreEqual(@"[""str_1"",""str_2"",""str_3""]", json);
}
public class ConstructorReadonlyFields
{
public readonly string A;
public readonly int B;
public ConstructorReadonlyFields(string a, int b)
{
A = a;
B = b;
}
}
[Test]
public void ConstructorReadonlyFieldsTest()
{
ConstructorReadonlyFields c1 = new ConstructorReadonlyFields("String!", int.MaxValue);
string json = JsonConvert.SerializeObject(c1, Formatting.Indented);
Assert.AreEqual(@"{
""A"": ""String!"",
""B"": 2147483647
}", json);
ConstructorReadonlyFields c2 = JsonConvert.DeserializeObject<ConstructorReadonlyFields>(json);
Assert.AreEqual("String!", c2.A);
Assert.AreEqual(int.MaxValue, c2.B);
}
public struct StructTest
{
public string StringProperty { get; set; }
public string StringField;
public int IntProperty { get; set; }
public int IntField;
}
[Test]
public void SerializeStruct()
{
StructTest structTest = new StructTest
{
StringProperty = "StringProperty!",
StringField = "StringField",
IntProperty = 5,
IntField = 10
};
string json = JsonConvert.SerializeObject(structTest, Formatting.Indented);
Console.WriteLine(json);
Assert.AreEqual(@"{
""StringField"": ""StringField"",
""IntField"": 10,
""StringProperty"": ""StringProperty!"",
""IntProperty"": 5
}", json);
StructTest deserialized = JsonConvert.DeserializeObject<StructTest>(json);
Assert.AreEqual(structTest.StringProperty, deserialized.StringProperty);
Assert.AreEqual(structTest.StringField, deserialized.StringField);
Assert.AreEqual(structTest.IntProperty, deserialized.IntProperty);
Assert.AreEqual(structTest.IntField, deserialized.IntField);
}
}
}
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Serialization
{
public class NullValueHandlingTests : TestFixtureBase
{
[Test]
public void NullValueHandlingSerialization()
{
Store s1 = new Store();
JsonSerializer jsonSerializer = new JsonSerializer();
jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
StringWriter sw = new StringWriter();
jsonSerializer.Serialize(sw, s1);
//JsonConvert.ConvertDateTimeToJavaScriptTicks(s1.Establised.DateTime)
Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000+0000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0}]}", sw.GetStringBuilder().ToString());
Store s2 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader("{}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s2.Escape);
Store s3 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Escape"":null}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s3.Escape);
Store s4 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(@"{""Color"":2,""Establised"":""\/Date(1264071600000+1300)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949485690000+1300)\/"",""Price"":0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946638000000)\/"",""Price"":0.0}]}")), typeof(Store));
Assert.AreEqual(s1.Establised, s3.Establised);
}
[Test]
public void NullValueHandlingBlogPost()
{
Movie movie = new Movie();
movie.Name = "Bad Boys III";
movie.Description = "It's no Bad Boys";
string included = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { });
// {
// "Name": "Bad Boys III",
// "Description": "It's no Bad Boys",
// "Classification": null,
// "Studio": null,
// "ReleaseDate": null,
// "ReleaseCountries": null
// }
string ignored = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
// {
// "Name": "Bad Boys III",
// "Description": "It's no Bad Boys"
// }
Assert.AreEqual(@"{
""Name"": ""Bad Boys III"",
""Description"": ""It's no Bad Boys"",
""Classification"": null,
""Studio"": null,
""ReleaseDate"": null,
""ReleaseCountries"": null
}", included);
Assert.AreEqual(@"{
""Name"": ""Bad Boys III"",
""Description"": ""It's no Bad Boys""
}", ignored);
}
}
}
@@ -327,12 +327,13 @@ namespace Newtonsoft.Json.Tests.Serialization
serializer.Deserialize(new StringReader(json), typeof(List<List<DateTime>>));
}
catch
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Assert.AreEqual(1, errors.Count);
Assert.AreEqual("Could not cast or convert from System.String to System.DateTime.", errors[0]);
Assert.AreEqual(@"Error converting value ""kjhkjhkjhkjh"" to type 'System.DateTime'.", errors[0]);
}
}
}
@@ -23,7 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT && !NET20
#if !PocketPC && !NET20
using System;
using System.IO;
using System.Linq;
@@ -61,7 +61,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("This value was reset after serialization.", obj.Member2);
Assert.AreEqual("This is a nonserialized value", obj.Member3);
Assert.AreEqual(null, obj.Member4);
Assert.AreEqual("Error message for member Member6 = Exception has been thrown by the target of an invocation.", obj.Member5);
Assert.AreEqual("Error message for member Member6 = Error getting value from 'Member6' on 'Newtonsoft.Json.Tests.TestObjects.SerializationEventTestObject'.", obj.Member5);
JObject o = JObject.Parse(@"{
""Member1"": 11,
@@ -76,7 +76,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("This value went into the data file during serialization.", obj.Member2);
Assert.AreEqual("This value was set during deserialization", obj.Member3);
Assert.AreEqual("This value was set after deserialization.", obj.Member4);
Assert.AreEqual("Error message for member Member6 = Exception has been thrown by the target of an invocation.", obj.Member5);
Assert.AreEqual("Error message for member Member6 = Error setting value to 'Member6' on 'Newtonsoft.Json.Tests.TestObjects.SerializationEventTestObject'.", obj.Member5);
}
[Test]
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class Car
{
// included in JSON
public string Model { get; set; }
public DateTime Year { get; set; }
public List<string> Features { get; set; }
// ignored
[JsonIgnore]
public DateTime LastModified { get; set; }
}
}
@@ -32,7 +32,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
{
public class CircularReferenceClass
{
[JsonProperty(IsRequired = true)]
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
public CircularReferenceClass Child { get; set; }
}
@@ -33,7 +33,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
[JsonObject(Id = "MyExplicitId")]
public class CircularReferenceWithIdClass
{
[JsonProperty(IsRequired = true)]
[JsonProperty(Required = Required.AllowNull)]
public string Name { get; set; }
public CircularReferenceWithIdClass Child { get; set; }
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
[DataContract]
public class Computer
{
// included in JSON
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal SalePrice { get; set; }
// ignored
public string Manufacture { get; set; }
public int StockCount { get; set; }
public decimal WholeSalePrice { get; set; }
public DateTime NextShipmentDate { get; set; }
}
}
@@ -32,9 +32,16 @@ namespace Newtonsoft.Json.Tests.TestObjects
{
public string Company { get; set; }
public decimal Amount { get; set; }
[DefaultValue(false)]
// false is default value of bool
public bool Paid { get; set; }
[DefaultValue(null)]
// null is default value of nullable
public DateTime? PaidDate { get; set; }
// customize default values
[DefaultValue(30)]
public int FollowUpDays { get; set; }
[DefaultValue("")]
public string FollowUpEmailAddress { get; set; }
}
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> ReleaseCountries { get; set; }
}
}
@@ -32,16 +32,16 @@ namespace Newtonsoft.Json.Tests.TestObjects
{
public class RequiredMembersClass
{
[JsonProperty(IsRequired = true)]
[JsonProperty(Required = Required.Always)]
public string FirstName { get; set; }
[JsonProperty]
public string MiddleName { get; set; }
[JsonProperty(IsRequired = true)]
[JsonProperty(Required = Required.AllowNull)]
public string LastName { get; set; }
[JsonProperty(IsRequired = true)]
[JsonProperty(Required = Required.Default)]
public DateTime BirthDate { get; set; }
}
}
@@ -23,7 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
using System.Collections.Generic;
using System.Runtime.Serialization;
@@ -23,7 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using Newtonsoft.Json.Tests.Serialization;
@@ -23,7 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT && !NET20
#if !PocketPC && !NET20
using System;
using System.Linq;
using System.Runtime.Serialization;
@@ -23,7 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
using System;
using System.Runtime.Serialization;
using Newtonsoft.Json.Serialization;
@@ -37,9 +37,11 @@ namespace Newtonsoft.Json.Tests.TestObjects
public int[] RoomsPerFloor = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public bool Open = false;
public char Symbol = '@';
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Mottos = new List<string>();
public decimal Cost = 100980.1M;
public string Escape = "\r\n\t\f\b?{\\r\\n\"\'";
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<Product> product = new List<Product>();
public Store()
@@ -25,9 +25,6 @@
using System;
using System.Collections.Generic;
#if !SILVERLIGHT && !PocketPC && !NET20
using System.Data.Linq;
#endif
#if !SILVERLIGHT
using System.Data.SqlTypes;
#endif
@@ -38,11 +35,22 @@ using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Converters
{
#if !SILVERLIGHT && !PocketPC && !NET20
internal interface IBinary
{
byte[] ToArray();
}
#endif
/// <summary>
/// Converts a binary value to and from a base 64 string value.
/// </summary>
public class BinaryConverter : JsonConverter
{
#if !SILVERLIGHT && !PocketPC && !NET20
private const string BinaryTypeName = "System.Data.Linq.Binary";
#endif
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
@@ -68,8 +76,11 @@ namespace Newtonsoft.Json.Converters
private byte[] GetByteArray(object value)
{
#if !SILVERLIGHT && !PocketPC && !NET20
if (value is Binary)
return ((Binary)value).ToArray();
if (value.GetType().AssignableToTypeName(BinaryTypeName))
{
IBinary binary = DynamicWrapper.CreateWrapper<IBinary>(value);
return binary.ToArray();
}
#endif
#if !SILVERLIGHT
if (value is SqlBinary)
@@ -110,8 +121,8 @@ namespace Newtonsoft.Json.Converters
return data;
#if !SILVERLIGHT && !PocketPC && !NET20
if (typeof(Binary).IsAssignableFrom(t))
return new Binary(data);
if (t.AssignableToTypeName(BinaryTypeName))
return Activator.CreateInstance(t, data);
#endif
#if !SILVERLIGHT
if (typeof(SqlBinary).IsAssignableFrom(t))
@@ -137,7 +148,7 @@ namespace Newtonsoft.Json.Converters
return true;
#if !SILVERLIGHT && !PocketPC && !NET20
if (typeof(Binary).IsAssignableFrom(t))
if (t.AssignableToTypeName(BinaryTypeName))
return true;
#endif
#if !SILVERLIGHT
@@ -26,17 +26,28 @@
#if !PocketPC && !SILVERLIGHT && !NET20
using System;
using System.Data;
using System.Reflection;
using Newtonsoft.Json.Serialization;
using System.Globalization;
using Newtonsoft.Json.Utilities;
using System.Linq;
using System.Reflection.Emit;
namespace Newtonsoft.Json.Converters
{
internal interface IEntityKeyMember
{
string Key { get; set; }
object Value { get; set; }
}
/// <summary>
/// Converts an Entity Framework EntityKey to and from JSON.
/// </summary>
public class EntityKeyMemberConverter : JsonConverter
{
private const string EntityKeyMemberFullTypeName = "System.Data.EntityKeyMember";
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
@@ -45,7 +56,7 @@ namespace Newtonsoft.Json.Converters
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
EntityKeyMember entityKeyMember = (EntityKeyMember) value;
IEntityKeyMember entityKeyMember = DynamicWrapper.CreateWrapper<IEntityKeyMember>(value);
Type keyType = (entityKeyMember.Value != null) ? entityKeyMember.Value.GetType() : null;
writer.WriteStartObject();
@@ -95,7 +106,7 @@ namespace Newtonsoft.Json.Converters
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
EntityKeyMember entityKeyMember = new EntityKeyMember();
IEntityKeyMember entityKeyMember = DynamicWrapper.CreateWrapper<IEntityKeyMember>(Activator.CreateInstance(objectType));
ReadAndAssertProperty(reader, "Key");
ReadAndAssert(reader);
@@ -113,7 +124,7 @@ namespace Newtonsoft.Json.Converters
ReadAndAssert(reader);
return entityKeyMember;
return DynamicWrapper.GetUnderlyingObject(entityKeyMember);
}
/// <summary>
@@ -125,7 +136,7 @@ namespace Newtonsoft.Json.Converters
/// </returns>
public override bool CanConvert(Type objectType)
{
return typeof(EntityKeyMember).IsAssignableFrom(objectType);
return (objectType.AssignableToTypeName(EntityKeyMemberFullTypeName));
}
}
}
Binary file not shown.
+13 -2
View File
@@ -13,6 +13,7 @@ namespace Newtonsoft.Json
internal NullValueHandling? _nullValueHandling;
internal DefaultValueHandling? _defaultValueHandling;
internal ReferenceLoopHandling? _referenceLoopHandling;
internal ObjectCreationHandling? _objectCreationHandling;
internal bool? _isReference;
/// <summary>
@@ -45,6 +46,16 @@ namespace Newtonsoft.Json
set { _referenceLoopHandling = value; }
}
/// <summary>
/// Gets or sets the object creation handling used when deserializing this property.
/// </summary>
/// <value>The object creation handling.</value>
public ObjectCreationHandling ObjectCreationHandling
{
get { return _objectCreationHandling ?? default(ObjectCreationHandling); }
set { _objectCreationHandling = value; }
}
/// <summary>
/// Gets or sets whether this property's value is serialized as a reference.
/// </summary>
@@ -65,9 +76,9 @@ namespace Newtonsoft.Json
/// Gets or sets a value indicating whether this property is required.
/// </summary>
/// <value>
/// <c>true</c> if this property is required; otherwise, <c>false</c>.
/// A value indicating whether this property is required.
/// </value>
public bool IsRequired { get; set; }
public Required Required { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonPropertyAttribute"/> class.
@@ -112,6 +112,7 @@
<Compile Include="Linq\JProperty.cs" />
<Compile Include="Linq\JValue.cs" />
<Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="Required.cs" />
<Compile Include="Schema\Extensions.cs" />
<Compile Include="Schema\JsonSchemaException.cs" />
<Compile Include="Schema\JsonSchemaModel.cs" />
@@ -128,10 +129,12 @@
<Compile Include="Serialization\DefaultContractResolver.cs" />
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\DynamicValueProvider.cs" />
<Compile Include="Serialization\ErrorContext.cs" />
<Compile Include="Serialization\ErrorEventArgs.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Serialization\IValueProvider.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
@@ -153,6 +156,7 @@
<Compile Include="Serialization\JsonSerializerProxy.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\OnErrorAttribute.cs" />
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="StreamingContext.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
@@ -160,6 +164,7 @@
<Compile Include="Utilities\CollectionWrapper.cs" />
<Compile Include="Utilities\DateTimeUtils.cs" />
<Compile Include="Utilities\DictionaryWrapper.cs" />
<Compile Include="Utilities\DynamicWrapper.cs" />
<Compile Include="Utilities\EnumUtils.cs" />
<Compile Include="Utilities\EnumValue.cs" />
<Compile Include="Utilities\EnumValues.cs" />
@@ -168,6 +173,7 @@
<Compile Include="JsonWriter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utilities\CollectionUtils.cs" />
<Compile Include="Utilities\LateBoundDelegateFactory.cs" />
<Compile Include="Utilities\ListWrapper.cs" />
<Compile Include="Utilities\MathUtils.cs" />
<Compile Include="Utilities\MiscellaneousUtils.cs" />
@@ -88,6 +88,7 @@
<Compile Include="Linq\ComponentModel\JTypeDescriptionProvider.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptor.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Required.cs" />
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="IJsonLineInfo.cs" />
@@ -146,9 +147,11 @@
<Compile Include="Serialization\CamelCasePropertyNamesContractResolver.cs" />
<Compile Include="Serialization\DefaultContractResolver.cs" />
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\DynamicValueProvider.cs" />
<Compile Include="Serialization\ErrorContext.cs" />
<Compile Include="Serialization\ErrorEventArgs.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\IValueProvider.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
@@ -171,6 +174,9 @@
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\OnErrorAttribute.cs" />
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="Utilities\DynamicWrapper.cs" />
<Compile Include="Utilities\LateBoundDelegateFactory.cs" />
<Compile Include="Utilities\ThreadSafeStore.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
@@ -14,6 +14,11 @@
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>false</ThrowErrorsInValidation>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -110,16 +115,19 @@
<Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
<Compile Include="Required.cs" />
<Compile Include="SerializationBinder.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolver.cs" />
<Compile Include="Serialization\DefaultContractResolver.cs" />
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\DynamicValueProvider.cs" />
<Compile Include="Serialization\ErrorContext.cs" />
<Compile Include="Serialization\ErrorEventArgs.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\IReferenceResolver.cs" />
<Compile Include="Serialization\IValueProvider.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
@@ -131,6 +139,7 @@
<Compile Include="Serialization\JsonSerializerInternalReader.cs" />
<Compile Include="Serialization\JsonSerializerInternalWriter.cs" />
<Compile Include="Serialization\OnErrorAttribute.cs" />
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="StreamingContext.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
@@ -139,10 +148,12 @@
<Compile Include="Utilities\ConvertUtils.cs" />
<Compile Include="Utilities\DateTimeUtils.cs" />
<Compile Include="Utilities\DictionaryWrapper.cs" />
<Compile Include="Utilities\DynamicWrapper.cs" />
<Compile Include="Utilities\EnumUtils.cs" />
<Compile Include="Utilities\EnumValue.cs" />
<Compile Include="Utilities\EnumValues.cs" />
<Compile Include="Utilities\JavaScriptUtils.cs" />
<Compile Include="Utilities\LateBoundDelegateFactory.cs" />
<Compile Include="Utilities\ListWrapper.cs" />
<Compile Include="Utilities\MathUtils.cs" />
<Compile Include="Utilities\MiscellaneousUtils.cs" />
@@ -169,7 +180,7 @@
<Compile Include="Schema\JsonSchemaType.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v3.0\Microsoft.Silverlight.CSharp.targets" Condition="" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+9 -6
View File
@@ -72,12 +72,6 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.Entity">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
@@ -94,6 +88,8 @@
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Required.cs" />
<Compile Include="Serialization\DynamicValueProvider.cs" />
<Compile Include="Serialization\ErrorEventArgs.cs" />
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProvider.cs" />
@@ -158,6 +154,7 @@
<Compile Include="Serialization\DefaultSerializationBinder.cs" />
<Compile Include="Serialization\ErrorContext.cs" />
<Compile Include="Serialization\IContractResolver.cs" />
<Compile Include="Serialization\IValueProvider.cs" />
<Compile Include="Serialization\JsonArrayContract.cs" />
<Compile Include="Serialization\JsonContract.cs" />
<Compile Include="Serialization\JsonDictionaryContract.cs" />
@@ -179,7 +176,10 @@
<Compile Include="Serialization\JsonSerializerProxy.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
<Compile Include="Serialization\CachedAttributeGetter.cs" />
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="Serialization\OnErrorAttribute.cs" />
<Compile Include="Utilities\DynamicWrapper.cs" />
<Compile Include="Utilities\LateBoundDelegateFactory.cs" />
<Compile Include="Utilities\ThreadSafeStore.cs" />
<Compile Include="TypeNameHandling.cs" />
<Compile Include="Utilities\BidirectionalDictionary.cs" />
@@ -220,5 +220,8 @@
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Dynamic.snk" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
@@ -51,6 +51,8 @@ using System.Security;
#endif
[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
[assembly: AssemblyDescription("")]
+9
View File
@@ -0,0 +1,9 @@
namespace Newtonsoft.Json
{
public enum Required
{
Default,
AllowNull,
Always
}
}
@@ -164,7 +164,7 @@ namespace Newtonsoft.Json.Schema
_resolver = resolver;
return GenerateInternal(type, !rootSchemaNullable);
return GenerateInternal(type, (!rootSchemaNullable) ? Required.Always : Required.Default);
}
private string GetTitle(Type type)
@@ -214,7 +214,7 @@ namespace Newtonsoft.Json.Schema
}
}
private JsonSchema GenerateInternal(Type type, bool valueRequired)
private JsonSchema GenerateInternal(Type type, Required valueRequired)
{
ValidationUtils.ArgumentNotNull(type, "type");
@@ -256,7 +256,7 @@ namespace Newtonsoft.Json.Schema
// can be converted to a string
if (typeof (IConvertible).IsAssignableFrom(keyType))
{
CurrentSchema.AdditionalProperties = GenerateInternal(valueType, false);
CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default);
}
}
}
@@ -274,7 +274,7 @@ namespace Newtonsoft.Json.Schema
if (collectionItemType != null)
{
CurrentSchema.Items = new List<JsonSchema>();
CurrentSchema.Items.Add(GenerateInternal(collectionItemType, !allowNullItem));
CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!allowNullItem) ? Required.Always : Required.Default));
}
}
else
@@ -295,8 +295,7 @@ namespace Newtonsoft.Json.Schema
{
if (!property.Ignored)
{
Type propertyMemberType = ReflectionUtils.GetMemberUnderlyingType(property.Member);
JsonSchema propertySchema = GenerateInternal(propertyMemberType, property.Required);
JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required);
if (property.DefaultValue != null)
propertySchema.Default = JToken.FromObject(property.DefaultValue);
@@ -336,10 +335,10 @@ namespace Newtonsoft.Json.Schema
return ((value & flag) == flag);
}
private JsonSchemaType GetJsonSchemaType(Type type, bool valueRequired)
private JsonSchemaType GetJsonSchemaType(Type type, Required valueRequired)
{
JsonSchemaType schemaType = JsonSchemaType.None;
if (!valueRequired && ReflectionUtils.IsNullable(type))
if (valueRequired != Required.Always && ReflectionUtils.IsNullable(type))
{
schemaType = JsonSchemaType.Null;
if (ReflectionUtils.IsNullableType(type))
@@ -32,9 +32,6 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json.Utilities;
#if !PocketPC && !SILVERLIGHT && !NET20
using System.Data.Objects.DataClasses;
#endif
namespace Newtonsoft.Json.Serialization
{
@@ -106,8 +103,9 @@ namespace Newtonsoft.Json.Serialization
}
#if !PocketPC && !SILVERLIGHT && !NET20
Type match;
// don't include EntityKey on entities objects... this is a bit hacky
if (typeof(EntityObject).IsAssignableFrom(objectType))
if (objectType.AssignableToTypeName("System.Data.Objects.DataClasses.EntityObject", out match))
serializableMembers = serializableMembers.Where(ShouldSerializeEntityMember).ToList();
#endif
@@ -120,7 +118,7 @@ namespace Newtonsoft.Json.Serialization
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
{
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(EntityReference<>))
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().FullName == "System.Data.Objects.DataClasses.EntityReference`1")
return false;
}
@@ -140,7 +138,7 @@ namespace Newtonsoft.Json.Serialization
contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType);
contract.Properties.AddRange(CreateProperties(contract));
if (contract.DefaultContstructor == null || contract.DefaultContstructor.IsPrivate)
if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
contract.ParametrizedConstructor = GetParametrizedConstructor(objectType);
return contract;
@@ -173,16 +171,32 @@ namespace Newtonsoft.Json.Serialization
}
#endif
contract.DefaultContstructor =
ReflectionUtils.GetDefaultConstructor(contract.CreatedType, false) ??
ReflectionUtils.GetDefaultConstructor(contract.CreatedType, true);
if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true)
|| contract.CreatedType.IsValueType)
{
#if !PocketPC
contract.DefaultCreator = LateBoundDelegateFactory.CreateDefaultConstructor(contract.CreatedType);
#else
ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(contract.CreatedType, true);
contract.DefaultCreator = () =>
{
if (contract.CreatedType.IsValueType)
return Activator.CreateInstance(contract.CreatedType);
return constructorInfo.Invoke(null);
};
#endif
contract.DefaultCreatorNonPublic = (!contract.CreatedType.IsValueType &&
ReflectionUtils.GetDefaultConstructor(contract.CreatedType) == null);
}
foreach (MethodInfo method in contract.UnderlyingType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
Type prevAttributeType = null;
ParameterInfo[] parameters = method.GetParameters();
#if !PocketPC && !SILVERLIGHT && !NET20
#if !PocketPC && !NET20
if (IsValidCallback(method, parameters, typeof(OnSerializingAttribute), contract.OnSerializing, ref prevAttributeType))
{
contract.OnSerializing = method;
@@ -303,7 +317,7 @@ namespace Newtonsoft.Json.Serialization
if (members == null)
throw new JsonSerializationException("Null collection of seralizable members returned.");
JsonPropertyCollection properties = new JsonPropertyCollection();
JsonPropertyCollection properties = new JsonPropertyCollection(contract);
foreach (MemberInfo member in members)
{
@@ -325,7 +339,13 @@ namespace Newtonsoft.Json.Serialization
protected virtual JsonProperty CreateProperty(JsonObjectContract contract, MemberInfo member)
{
JsonProperty property = new JsonProperty();
property.Member = member;
property.PropertyType = ReflectionUtils.GetMemberUnderlyingType(member);
#if !PocketPC
property.ValueProvider = new DynamicValueProvider(member);
#else
property.ValueProvider = new ReflectionValueProvider(member);
#endif
property.Converter = JsonTypeReflector.GetConverter(member, property.PropertyType);
#if !PocketPC && !NET20
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType);
@@ -353,13 +373,13 @@ namespace Newtonsoft.Json.Serialization
property.PropertyName = ResolvePropertyName(mappedName);
if (propertyAttribute != null)
property.Required = propertyAttribute.IsRequired;
property.Required = propertyAttribute.Required;
#if !PocketPC && !NET20
else if (dataMemberAttribute != null)
property.Required = dataMemberAttribute.IsRequired;
property.Required = (dataMemberAttribute.IsRequired) ? Required.AllowNull : Required.Default;
#endif
else
property.Required = false;
property.Required = Required.Default;
property.Ignored = (hasIgnoreAttribute ||
(contract.MemberSerialization == MemberSerialization.OptIn
@@ -380,6 +400,7 @@ namespace Newtonsoft.Json.Serialization
property.NullValueHandling = (propertyAttribute != null) ? propertyAttribute._nullValueHandling : null;
property.DefaultValueHandling = (propertyAttribute != null) ? propertyAttribute._defaultValueHandling : null;
property.ReferenceLoopHandling = (propertyAttribute != null) ? propertyAttribute._referenceLoopHandling : null;
property.ObjectCreationHandling = (propertyAttribute != null) ? propertyAttribute._objectCreationHandling : null;
property.IsReference = (propertyAttribute != null) ? propertyAttribute._isReference : null;
return property;
@@ -0,0 +1,55 @@
#if !PocketPC
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Newtonsoft.Json.Utilities;
using System.Globalization;
namespace Newtonsoft.Json.Serialization
{
public class DynamicValueProvider : IValueProvider
{
private readonly MemberInfo _memberInfo;
private Func<object, object> _getter;
private Action<object, object> _setter;
public DynamicValueProvider(MemberInfo memberInfo)
{
ValidationUtils.ArgumentNotNull(memberInfo, "memberInfo");
_memberInfo = memberInfo;
}
public void SetValue(object target, object value)
{
try
{
if (_setter == null)
_setter = LateBoundDelegateFactory.CreateSet<object>(_memberInfo);
_setter(target, value);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error setting value to '{0}' on '{1}'.".FormatWith(CultureInfo.InvariantCulture, _memberInfo.Name, target.GetType()), ex);
}
}
public object GetValue(object target)
{
try
{
if (_getter == null)
_getter = LateBoundDelegateFactory.CreateGet<object>(_memberInfo);
return _getter(target);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error getting value from '{0}' on '{1}'.".FormatWith(CultureInfo.InvariantCulture, _memberInfo.Name, target.GetType()), ex);
}
}
}
}
#endif
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Newtonsoft.Json.Serialization
{
public interface IValueProvider
{
void SetValue(object target, object value);
object GetValue(object target);
}
}
@@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Serialization
private bool _isCollectionItemTypeNullableType;
private Type _genericCollectionDefinitionType;
private Type _genericWrapperType;
private ConstructorInfo _genericWrapperConstructor;
private MemberHandler<object> _genericWrapperCreator;
/// <summary>
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
@@ -80,10 +80,16 @@ namespace Newtonsoft.Json.Serialization
if (_genericWrapperType == null)
{
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType);
_genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
#if !PocketPC
_genericWrapperCreator = LateBoundDelegateFactory.CreateMethodHandler(genericWrapperConstructor);
#else
_genericWrapperCreator = (target, args) => genericWrapperConstructor.Invoke(new[] { args[0] });
#endif
}
return (IWrappedCollection)_genericWrapperConstructor.Invoke(new[] { list });
return (IWrappedCollection)_genericWrapperCreator(null, list);
}
private bool IsTypeGenericCollectionInterface(Type type)
@@ -53,10 +53,10 @@ namespace Newtonsoft.Json.Serialization
/// <value>Whether this type contract is serialized as a reference.</value>
public bool? IsReference { get; set; }
private static readonly StreamingContext SerializationStreamingContextParameter = new StreamingContext(StreamingContextStates.All);
private static readonly StreamingContext SerializationStreamingContextParameter = new StreamingContext();
private static readonly object[] SerializationEventParameterValues = new object[] { SerializationStreamingContextParameter };
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
/// <summary>
/// Gets or sets the method called immediately after deserialization of the object.
/// </summary>
@@ -79,11 +79,8 @@ namespace Newtonsoft.Json.Serialization
public MethodInfo OnSerializing { get; set; }
#endif
/// <summary>
/// Gets or sets the default contstructor used to create the object.
/// </summary>
/// <value>The default contstructor.</value>
public ConstructorInfo DefaultContstructor { get; set; }
public Func<object> DefaultCreator { get; set; }
public bool DefaultCreatorNonPublic { get; set; }
/// <summary>
/// Gets or sets the method called when an error is thrown during the serialization of the object.
@@ -93,7 +90,7 @@ namespace Newtonsoft.Json.Serialization
internal void InvokeOnSerializing(object o)
{
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
if (OnSerializing != null)
OnSerializing.Invoke(o, SerializationEventParameterValues);
#endif
@@ -101,7 +98,7 @@ namespace Newtonsoft.Json.Serialization
internal void InvokeOnSerialized(object o)
{
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
if (OnSerialized != null)
OnSerialized.Invoke(o, SerializationEventParameterValues);
#endif
@@ -109,7 +106,7 @@ namespace Newtonsoft.Json.Serialization
internal void InvokeOnDeserializing(object o)
{
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
if (OnDeserializing != null)
OnDeserializing.Invoke(o, SerializationEventParameterValues);
#endif
@@ -117,7 +114,7 @@ namespace Newtonsoft.Json.Serialization
internal void InvokeOnDeserialized(object o)
{
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
if (OnDeserialized != null)
OnDeserialized.Invoke(o, SerializationEventParameterValues);
#endif
@@ -39,9 +39,9 @@ namespace Newtonsoft.Json.Serialization
internal Type DictionaryKeyType { get; private set; }
internal Type DictionaryValueType { get; private set; }
private Type _genericCollectionDefinitionType;
private readonly Type _genericCollectionDefinitionType;
private Type _genericWrapperType;
private ConstructorInfo _genericWrapperConstructor;
private MemberHandler<object> _genericWrapperCreator;
/// <summary>
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
@@ -83,10 +83,16 @@ namespace Newtonsoft.Json.Serialization
if (_genericWrapperType == null)
{
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(DictionaryWrapper<,>), DictionaryKeyType, DictionaryValueType);
_genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
#if !PocketPC
_genericWrapperCreator = LateBoundDelegateFactory.CreateMethodHandler(genericWrapperConstructor);
#else
_genericWrapperCreator = (target, args) => genericWrapperConstructor.Invoke(new[] { args[0] });
#endif
}
return (IWrappedDictionary)_genericWrapperConstructor.Invoke(new[] { dictionary });
return (IWrappedDictionary)_genericWrapperCreator(null, dictionary);
}
private bool IsTypeGenericDictionaryInterface(Type type)
@@ -58,7 +58,7 @@ namespace Newtonsoft.Json.Serialization
public JsonObjectContract(Type underlyingType)
: base(underlyingType)
{
Properties = new JsonPropertyCollection();
Properties = new JsonPropertyCollection(this);
CreatedType = underlyingType;
}
}
@@ -24,6 +24,7 @@
#endregion
using System.Reflection;
using System;
namespace Newtonsoft.Json.Serialization
{
@@ -39,10 +40,14 @@ namespace Newtonsoft.Json.Serialization
public string PropertyName { get; set; }
/// <summary>
/// Gets the member.
/// Gets the <see cref="IValueProvider"/> that will get and set the <see cref="JsonProperty"/> during serialization.
/// </summary>
/// <value>The member.</value>
public MemberInfo Member { get; set; }
/// <value>The <see cref="IValueProvider"/> that will get and set the <see cref="JsonProperty"/> during serialization.</value>
public IValueProvider ValueProvider { get; set; }
public Type PropertyType { get; set; }
public JsonConverter Converter { get; set; }
/// <summary>
/// Gets a value indicating whether this <see cref="JsonProperty"/> is ignored.
@@ -77,8 +82,8 @@ namespace Newtonsoft.Json.Serialization
/// <summary>
/// Gets a value indicating whether this <see cref="JsonProperty"/> is required.
/// </summary>
/// <value><c>true</c> if required; otherwise, <c>false</c>.</value>
public bool Required { get; set; }
/// <value>A value indicating whether this <see cref="JsonProperty"/> is required.</value>
public Required Required { get; set; }
/// <summary>
/// Gets a value indicating whether this property preserves object references.
@@ -105,5 +110,11 @@ namespace Newtonsoft.Json.Serialization
/// </summary>
/// <value>The reference loop handling.</value>
public ReferenceLoopHandling? ReferenceLoopHandling { get; set; }
/// <summary>
/// Gets the property object creation handling.
/// </summary>
/// <value>The object creation handling.</value>
public ObjectCreationHandling? ObjectCreationHandling { get; set; }
}
}
@@ -37,6 +37,14 @@ namespace Newtonsoft.Json.Serialization
/// </summary>
public class JsonPropertyCollection : KeyedCollection<string, JsonProperty>
{
private readonly JsonObjectContract _contract;
public JsonPropertyCollection(JsonObjectContract contract)
{
ValidationUtils.ArgumentNotNull(contract, "contract");
_contract = contract;
}
/// <summary>
/// When implemented in a derived class, extracts the key from the specified element.
/// </summary>
@@ -63,7 +71,7 @@ namespace Newtonsoft.Json.Serialization
if (!existingProperty.Ignored)
throw new JsonSerializationException(
"A member with the name '{0}' already exists on '{1}'. Use the JsonPropertyAttribute to specify another name.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, property.Member.DeclaringType));
"A member with the name '{0}' already exists on '{1}'. Use the JsonPropertyAttribute to specify another name.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, _contract.UnderlyingType));
// remove ignored property so it can be replaced in collection
Remove(existingProperty);
@@ -30,6 +30,7 @@ using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
@@ -56,7 +57,10 @@ namespace Newtonsoft.Json.Serialization
if (reader.TokenType == JsonToken.StartArray)
{
PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, null, GetArrayContract(objectType));
if (contract is JsonArrayContract)
PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, null, (JsonArrayContract)contract);
else
throw new JsonSerializationException("Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
}
else if (reader.TokenType == JsonToken.StartObject)
{
@@ -75,7 +79,7 @@ namespace Newtonsoft.Json.Serialization
else if (contract is JsonObjectContract)
PopulateObject(target, reader, (JsonObjectContract) contract, id);
else
throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
throw new JsonSerializationException("Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
}
}
@@ -162,14 +166,14 @@ namespace Newtonsoft.Json.Serialization
return CreateList(reader, objectType, existingValue, null);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Date:
// convert empty string to null automatically
if (reader.Value is string &&
string.IsNullOrEmpty((string)reader.Value) &&
return EnsureType(reader.Value, objectType);
case JsonToken.String:
// convert empty string to null automatically for nullable types
if (string.IsNullOrEmpty((string)reader.Value) &&
objectType != null &&
ReflectionUtils.IsNullable(objectType))
ReflectionUtils.IsNullableType(objectType))
return null;
return EnsureType(reader.Value, objectType);
@@ -183,7 +187,7 @@ namespace Newtonsoft.Json.Serialization
if (objectType == typeof (DBNull))
return DBNull.Value;
return null;
return EnsureType(reader.Value, objectType);
case JsonToken.Comment:
// ignore
break;
@@ -297,7 +301,7 @@ namespace Newtonsoft.Json.Serialization
return PopulateObject(existingValue, reader, (JsonObjectContract) contract, id);
}
throw new JsonSerializationException("Expected a JsonObjectContract or JsonDictionaryContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
}
private JsonArrayContract GetArrayContract(Type objectType)
@@ -308,7 +312,7 @@ namespace Newtonsoft.Json.Serialization
JsonArrayContract arrayContract = contract as JsonArrayContract;
if (arrayContract == null)
throw new JsonSerializationException("Expected a JsonArrayContract for type '{0}', got '{1}'.".FormatWith(CultureInfo.InvariantCulture, objectType, contract.GetType()));
throw new JsonSerializationException("Cannot deserialize JSON array into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
return arrayContract;
}
@@ -345,23 +349,39 @@ namespace Newtonsoft.Json.Serialization
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 valueType = ReflectionUtils.GetObjectType(value);
// 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);
{
try
{
return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, FormatValueForPrint(value), targetType), ex);
}
}
return value;
}
private string FormatValueForPrint(object value)
{
if (value == null)
return "{null}";
if (value is string)
return @"""" + value + @"""";
return value.ToString();
}
private void SetObjectMember(JsonReader reader, object target, JsonObjectContract contract, string memberName)
{
JsonProperty property;
@@ -388,19 +408,19 @@ namespace Newtonsoft.Json.Serialization
return;
}
// get the member's underlying type
Type memberType = ReflectionUtils.GetMemberUnderlyingType(property.Member);
object currentValue = null;
bool useExistingValue = false;
if ((Serializer.ObjectCreationHandling == ObjectCreationHandling.Auto || Serializer.ObjectCreationHandling == ObjectCreationHandling.Reuse)
ObjectCreationHandling objectCreationHandling =
property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
&& property.Readable)
{
currentValue = ReflectionUtils.GetMemberValue(property.Member, target);
currentValue = property.ValueProvider.GetValue(target);
useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericDefinition(memberType, typeof(ReadOnlyCollection<>)));
useExistingValue = (currentValue != null && !property.PropertyType.IsArray && !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof(ReadOnlyCollection<>)));
}
if (!property.Writable && !useExistingValue)
@@ -409,10 +429,10 @@ namespace Newtonsoft.Json.Serialization
return;
}
object value = CreateValue(reader, memberType, (useExistingValue) ? currentValue : null, JsonTypeReflector.GetConverter(property.Member, memberType));
object value = CreateValue(reader, property.PropertyType, (useExistingValue) ? currentValue : null, property.Converter);
if (!useExistingValue && ShouldSetPropertyValue(property, value))
ReflectionUtils.SetMemberValue(property.Member, target, value);
property.ValueProvider.SetValue(target, value);
}
private bool ShouldSetPropertyValue(JsonProperty property, object value)
@@ -431,7 +451,7 @@ namespace Newtonsoft.Json.Serialization
private object CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, string id)
{
IWrappedDictionary dictionary = contract.CreateWrapper(contract.DefaultContstructor.Invoke(null));
IWrappedDictionary dictionary = contract.CreateWrapper(contract.DefaultCreator());
PopulateDictionary(dictionary, reader, contract, id);
@@ -486,7 +506,7 @@ namespace Newtonsoft.Json.Serialization
if (reference != null && isTemporaryListReference)
throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#if !PocketPC && !SILVERLIGHT
#if !PocketPC
if (contract.OnSerializing != null && isTemporaryListReference)
throw new JsonSerializationException("Cannot call OnSerializing on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
#endif
@@ -541,16 +561,19 @@ namespace Newtonsoft.Json.Serialization
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id)
{
object newObject;
object newObject = null;
if (contract.UnderlyingType.IsInterface || contract.UnderlyingType.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, contract.UnderlyingType));
if (contract.DefaultContstructor != null &&
(contract.DefaultContstructor.IsPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
if (contract.DefaultCreator != null &&
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
{
newObject = contract.DefaultContstructor.Invoke(null);
newObject = contract.DefaultCreator();
}
if (newObject != null)
{
PopulateObject(newObject, reader, contract, id);
return newObject;
}
@@ -585,8 +608,7 @@ namespace Newtonsoft.Json.Serialization
{
if (!property.Ignored)
{
Type memberType = ReflectionUtils.GetMemberUnderlyingType(property.Member);
propertyValues[property] = CreateValue(reader, memberType, null, property.MemberConverter);
propertyValues[property] = CreateValue(reader, property.PropertyType, null, property.MemberConverter);
}
}
else
@@ -627,8 +649,11 @@ namespace Newtonsoft.Json.Serialization
// go through unused values and set the newly created object's properties
foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
{
JsonProperty property = remainingPropertyValue.Key;
object value = remainingPropertyValue.Value;
if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value))
ReflectionUtils.SetMemberValue(remainingPropertyValue.Key.Member, createdObject, remainingPropertyValue.Value);
property.ValueProvider.SetValue(createdObject, value);
}
contract.InvokeOnDeserialized(createdObject);
@@ -639,8 +664,8 @@ namespace Newtonsoft.Json.Serialization
{
contract.InvokeOnDeserializing(newObject);
Dictionary<string, bool> requiredProperties =
contract.Properties.Where(m => m.Required).ToDictionary(m => m.PropertyName, m => false);
Dictionary<JsonProperty, RequiredValue> requiredProperties =
contract.Properties.Where(m => m.Required != Required.Default).ToDictionary(m => m, m => RequiredValue.None);
if (id != null)
Serializer.ReferenceResolver.AddReference(id, newObject);
@@ -657,8 +682,7 @@ namespace Newtonsoft.Json.Serialization
if (!reader.Read())
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
// set required property even if null (matches WCF IsRequired behavour)
SetRequiredProperty(memberName, requiredProperties);
SetRequiredProperty(reader, memberName, contract, requiredProperties);
try
{
@@ -673,10 +697,12 @@ namespace Newtonsoft.Json.Serialization
}
break;
case JsonToken.EndObject:
foreach (KeyValuePair<string, bool> requiredProperty in requiredProperties)
foreach (KeyValuePair<JsonProperty, RequiredValue> requiredProperty in requiredProperties)
{
if (!requiredProperty.Value)
throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key));
if (requiredProperty.Value == RequiredValue.None)
throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName));
if (requiredProperty.Key.Required == Required.Always && requiredProperty.Value == RequiredValue.Null)
throw new JsonSerializationException("Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName));
}
contract.InvokeOnDeserialized(newObject);
@@ -692,24 +718,14 @@ namespace Newtonsoft.Json.Serialization
throw new JsonSerializationException("Unexpected end when deserializing object.");
}
private void SetRequiredProperty(string memberName, Dictionary<string, bool> requiredProperties)
private void SetRequiredProperty(JsonReader reader, string memberName, JsonObjectContract contract, Dictionary<JsonProperty, RequiredValue> requiredProperties)
{
// first attempt to find exact case match
// then attempt case insensitive match
if (requiredProperties.ContainsKey(memberName))
JsonProperty property = requiredProperties.Keys.ForgivingCaseSensitiveFind(p => p.PropertyName, memberName);
if (property != null)
{
requiredProperties[memberName] = true;
}
else
{
foreach (KeyValuePair<string, bool> requiredProperty in requiredProperties)
{
if (string.Compare(requiredProperty.Key, requiredProperty.Key, StringComparison.OrdinalIgnoreCase) == 0)
{
requiredProperties[requiredProperty.Key] = true;
break;
}
}
requiredProperties[property] = (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.Undefined)
? RequiredValue.Null
: RequiredValue.Value;
}
}
@@ -724,5 +740,12 @@ namespace Newtonsoft.Json.Serialization
reader.Read();
}
}
internal enum RequiredValue
{
None,
Null,
Value
}
}
}
@@ -168,34 +168,32 @@ namespace Newtonsoft.Json.Serialization
private void WriteMemberInfoProperty(JsonWriter writer, object value, JsonProperty property)
{
MemberInfo member = property.Member;
string propertyName = property.PropertyName;
JsonConverter memberConverter = property.MemberConverter;
object defaultValue = property.DefaultValue;
if (!ReflectionUtils.IsIndexedProperty(member))
object memberValue = property.ValueProvider.GetValue(value);
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore &&
memberValue == null)
return;
if (property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling) ==
DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
return;
if (ShouldWriteReference(memberValue, property))
{
object memberValue = ReflectionUtils.GetMemberValue(member, value);
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && memberValue == null)
return;
if (property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
return;
if (ShouldWriteReference(memberValue, property))
{
writer.WritePropertyName(propertyName ?? member.Name);
WriteReference(writer, memberValue);
return;
}
if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling))
return;
writer.WritePropertyName(propertyName ?? member.Name);
SerializeValue(writer, memberValue, memberConverter);
writer.WritePropertyName(propertyName);
WriteReference(writer, memberValue);
return;
}
if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling))
return;
writer.WritePropertyName(propertyName);
SerializeValue(writer, memberValue, memberConverter);
}
private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling)
@@ -260,10 +258,8 @@ namespace Newtonsoft.Json.Serialization
if (TryConvertToString(value, contract.UnderlyingType, out s))
{
writer.WriteValue(s);
#if !SILVERLIGHT && !PocketPC
contract.InvokeOnSerialized(value);
#endif
return;
}
@@ -292,7 +288,7 @@ namespace Newtonsoft.Json.Serialization
}
catch (Exception ex)
{
if (IsErrorHandled(value, contract, property.Member.Name, ex))
if (IsErrorHandled(value, contract, property.PropertyName, ex))
HandleError(writer, initialDepth);
else
throw;
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Newtonsoft.Json.Utilities;
using System.Globalization;
namespace Newtonsoft.Json.Serialization
{
public class ReflectionValueProvider : IValueProvider
{
private readonly MemberInfo _memberInfo;
public ReflectionValueProvider(MemberInfo memberInfo)
{
ValidationUtils.ArgumentNotNull(memberInfo, "memberInfo");
_memberInfo = memberInfo;
}
public void SetValue(object target, object value)
{
try
{
ReflectionUtils.SetMemberValue(_memberInfo, target, value);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error setting value to '{0}' on '{1}'.".FormatWith(CultureInfo.InvariantCulture, _memberInfo.Name, target.GetType()), ex);
}
}
public object GetValue(object target)
{
try
{
return ReflectionUtils.GetMemberValue(_memberInfo, target);
}
catch (Exception ex)
{
throw new JsonSerializationException("Error getting value from '{0}' on '{1}'.".FormatWith(CultureInfo.InvariantCulture, _memberInfo.Name, target.GetType()), ex);
}
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
#if PocketPC || SILVERLIGHT
#if PocketPC
#pragma warning disable 1591
// This class is... borrowed from .NET and Microsoft for a short time.
@@ -0,0 +1,279 @@
#if !SILVERLIGHT && !PocketPC
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Text;
using System.Threading;
using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
public class DynamicWrapperBase
{
internal protected object UnderlyingObject;
}
public static class DynamicWrapper
{
private static readonly object _lock = new object();
private static readonly WrapperDictionary _wrapperDictionary = new WrapperDictionary();
private static ModuleBuilder _moduleBuilder;
private static ModuleBuilder ModuleBuilder
{
get
{
Init();
return _moduleBuilder;
}
}
private static void Init()
{
if (_moduleBuilder == null)
{
lock (_lock)
{
if (_moduleBuilder == null)
{
AssemblyName assemblyName = new AssemblyName("Newtonsoft.Json.Dynamic");
assemblyName.KeyPair = new StrongNameKeyPair(GetStrongKey());
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
_moduleBuilder = assembly.DefineDynamicModule("Newtonsoft.Json.DynamicModule", false);
}
}
}
}
private static byte[] GetStrongKey()
{
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Newtonsoft.Json.Dynamic.snk"))
{
if (stream == null)
throw new MissingManifestResourceException("Should have a Newtonsoft.Json.Dynamic.snk as an embedded resource.");
int length = (int)stream.Length;
byte[] buffer = new byte[length];
stream.Read(buffer, 0, length);
return buffer;
}
}
public static Type GetWrapper(Type interfaceType, Type realObjectType)
{
Type wrapperType = _wrapperDictionary.GetType(interfaceType, realObjectType);
if (wrapperType == null)
{
wrapperType = GenerateWrapperType(interfaceType, realObjectType);
_wrapperDictionary.SetType(interfaceType, realObjectType, wrapperType);
}
return wrapperType;
}
public static object GetUnderlyingObject(object wrapper)
{
DynamicWrapperBase wrapperBase = wrapper as DynamicWrapperBase;
if (wrapperBase == null)
throw new ArgumentException("Object is not a wrapper.", "wrapper");
return wrapperBase.UnderlyingObject;
}
private static Type GenerateWrapperType(Type interfaceType, Type underlyingType)
{
TypeBuilder wrapperBuilder = ModuleBuilder.DefineType(
"{0}_{1}_Wrapper".FormatWith(CultureInfo.InvariantCulture, interfaceType.Name, underlyingType.Name),
TypeAttributes.NotPublic | TypeAttributes.Sealed,
typeof(DynamicWrapperBase),
new[] { interfaceType });
WrapperMethodBuilder wrapperMethod = new WrapperMethodBuilder(underlyingType, wrapperBuilder);
foreach (MethodInfo method in interfaceType.AllMethods())
{
wrapperMethod.Generate(method);
}
return wrapperBuilder.CreateType();
}
public static T CreateWrapper<T>(object realObject) where T : class
{
var dynamicType = GetWrapper(typeof(T), realObject.GetType());
var dynamicWrapper = (DynamicWrapperBase)Activator.CreateInstance(dynamicType);
dynamicWrapper.UnderlyingObject = realObject;
return dynamicWrapper as T;
}
}
internal class WrapperMethodBuilder
{
private readonly Type _realObjectType;
private readonly TypeBuilder _wrapperBuilder;
public WrapperMethodBuilder(Type realObjectType, TypeBuilder proxyBuilder)
{
_realObjectType = realObjectType;
_wrapperBuilder = proxyBuilder;
}
public void Generate(MethodInfo newMethod)
{
if (newMethod.IsGenericMethod)
newMethod = newMethod.GetGenericMethodDefinition();
FieldInfo srcField = typeof(DynamicWrapperBase).GetField("UnderlyingObject", BindingFlags.Instance | BindingFlags.NonPublic);
var parameters = newMethod.GetParameters();
var parameterTypes = parameters.Select(parameter => parameter.ParameterType).ToArray();
MethodBuilder methodBuilder = _wrapperBuilder.DefineMethod(
newMethod.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
newMethod.ReturnType,
parameterTypes);
if (newMethod.IsGenericMethod)
{
methodBuilder.DefineGenericParameters(
newMethod.GetGenericArguments().Select(arg => arg.Name).ToArray());
}
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
LoadUnderlyingObject(ilGenerator, srcField);
PushParameters(parameters, ilGenerator);
ExecuteMethod(newMethod, parameterTypes, ilGenerator);
Return(ilGenerator);
}
private static void Return(ILGenerator ilGenerator)
{
ilGenerator.Emit(OpCodes.Ret);
}
private void ExecuteMethod(MethodBase newMethod, Type[] parameterTypes, ILGenerator ilGenerator)
{
MethodInfo srcMethod = GetMethod(newMethod, parameterTypes);
if (srcMethod == null)
throw new MissingMethodException("Unable to find method " + newMethod.Name + " on " + _realObjectType.FullName);
ilGenerator.Emit(OpCodes.Call, srcMethod);
}
private MethodInfo GetMethod(MethodBase realMethod, Type[] parameterTypes)
{
if (realMethod.IsGenericMethod)
return _realObjectType.GetGenericMethod(realMethod.Name, parameterTypes);
return _realObjectType.GetMethod(realMethod.Name, parameterTypes);
}
private static void PushParameters(ICollection<ParameterInfo> parameters, ILGenerator ilGenerator)
{
for (int i = 1; i < parameters.Count + 1; i++)
ilGenerator.Emit(OpCodes.Ldarg, i);
}
private static void LoadUnderlyingObject(ILGenerator ilGenerator, FieldInfo srcField)
{
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, srcField);
}
}
internal class WrapperDictionary
{
private readonly Dictionary<string, Type> _wrapperTypes = new Dictionary<string, Type>();
private static string GenerateKey(Type interfaceType, Type realObjectType)
{
return interfaceType.Name + "_" + realObjectType.Name;
}
public Type GetType(Type interfaceType, Type realObjectType)
{
string key = GenerateKey(interfaceType, realObjectType);
if (_wrapperTypes.ContainsKey(key))
return _wrapperTypes[key];
return null;
}
public void SetType(Type interfaceType, Type realObjectType, Type wrapperType)
{
string key = GenerateKey(interfaceType, realObjectType);
if (_wrapperTypes.ContainsKey(key))
_wrapperTypes[key] = wrapperType;
else
_wrapperTypes.Add(key, wrapperType);
}
}
public static class TypeExtensions
{
public static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes)
{
var methods = type.GetMethods().Where(method => method.Name == name);
foreach (var method in methods)
{
if (method.HasParameters(parameterTypes))
return method;
}
return null;
}
public static bool HasParameters(this MethodInfo method, params Type[] parameterTypes)
{
var methodParameters = method.GetParameters().Select(parameter => parameter.ParameterType).ToArray();
if (methodParameters.Length != parameterTypes.Length)
return false;
for (int i = 0; i < methodParameters.Length; i++)
if (methodParameters[i].ToString() != parameterTypes[i].ToString())
return false;
return true;
}
public static IEnumerable<Type> AllInterfaces(this Type target)
{
foreach (var IF in target.GetInterfaces())
{
yield return IF;
foreach (var childIF in IF.AllInterfaces())
{
yield return childIF;
}
}
}
public static IEnumerable<MethodInfo> AllMethods(this Type target)
{
var allTypes = target.AllInterfaces().ToList();
allTypes.Add(target);
return from type in allTypes
from method in type.GetMethods()
select method;
}
}
}
#endif
@@ -0,0 +1,231 @@
#if !PocketPC
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
internal static class LateBoundDelegateFactory
{
public static Func<T, object> CreateGet<T>(MemberInfo memberInfo)
{
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
return CreateGet<T>(propertyInfo);
FieldInfo fieldInfo = memberInfo as FieldInfo;
if (fieldInfo != null)
return CreateGet<T>(fieldInfo);
throw new Exception("Could not create getter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo));
}
private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner)
{
DynamicMethod dynamicMethod = !owner.IsInterface
? new DynamicMethod(name, returnType, parameterTypes, owner, true)
: new DynamicMethod(name, returnType, parameterTypes, (Module)null, true);
return dynamicMethod;
}
public static Action<T, object> CreateSet<T>(MemberInfo memberInfo)
{
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
return CreateSet<T>(propertyInfo);
FieldInfo fieldInfo = memberInfo as FieldInfo;
if (fieldInfo != null)
return CreateSet<T>(fieldInfo);
throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo));
}
public static MemberHandler<object> CreateMethodHandler(MethodBase method)
{
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
ParameterInfo[] args = method.GetParameters();
Label argsOk = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldlen);
generator.Emit(OpCodes.Ldc_I4, args.Length);
generator.Emit(OpCodes.Beq, argsOk);
generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Throw);
generator.MarkLabel(argsOk);
if (!method.IsConstructor)
generator.PushInstance(method.DeclaringType);
for (int i = 0; i < args.Length; i++)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Ldelem_Ref);
generator.UnboxIfNeeded(args[i].ParameterType);
}
if (method.IsConstructor)
generator.Emit(OpCodes.Newobj, (ConstructorInfo)method);
else if (method.IsFinal || !method.IsVirtual)
generator.Emit(OpCodes.Call, (MethodInfo)method);
else
generator.Emit(OpCodes.Callvirt, (MethodInfo)method);
Type returnType = method.IsConstructor
? method.DeclaringType
: ((MethodInfo)method).ReturnType;
if (returnType != typeof(void))
generator.BoxIfNeeded(returnType);
else
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Ret);
return (MemberHandler<object>)dynamicMethod.CreateDelegate(typeof(MemberHandler<object>));
}
public static Func<object> CreateDefaultConstructor(Type type)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Create" + type.FullName, typeof(object), Type.EmptyTypes, type);
dynamicMethod.InitLocals = true;
ILGenerator generator = dynamicMethod.GetILGenerator();
if (type.IsValueType)
{
generator.DeclareLocal(type);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Box, type);
}
else
{
ConstructorInfo constructorInfo =
type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null,
Type.EmptyTypes, null);
if (constructorInfo == null)
throw new Exception("Could not get constructor for {0}.".FormatWith(CultureInfo.InvariantCulture, type));
generator.Emit(OpCodes.Newobj, constructorInfo);
}
generator.Emit(OpCodes.Ret);
return (Func<object>)dynamicMethod.CreateDelegate(typeof(Func<object>));
}
public static Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
{
MethodInfo getMethod = propertyInfo.GetGetMethod(true);
if (getMethod == null)
throw new Exception("Property '{0}' does not have a getter.".FormatWith(CultureInfo.InvariantCulture,
propertyInfo.Name));
DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(T), new[] { typeof(object) }, propertyInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
if (!getMethod.IsStatic)
generator.PushInstance(propertyInfo.DeclaringType);
if (getMethod.IsFinal || !getMethod.IsVirtual)
generator.Emit(OpCodes.Call, getMethod);
else
generator.Emit(OpCodes.Callvirt, getMethod);
generator.BoxIfNeeded(propertyInfo.PropertyType);
generator.Emit(OpCodes.Ret);
return (Func<T, object>)dynamicMethod.CreateDelegate(typeof(Func<T, object>));
}
static void PushInstance(this ILGenerator generator, Type type)
{
generator.Emit(OpCodes.Ldarg_0);
if (type.IsValueType)
generator.Emit(OpCodes.Unbox, type);
}
static void BoxIfNeeded(this ILGenerator generator, Type type)
{
if (type.IsValueType)
generator.Emit(OpCodes.Box, type);
}
static void UnboxIfNeeded(this ILGenerator generator, Type type)
{
if (type.IsValueType)
generator.Emit(OpCodes.Unbox_Any, type);
}
public static Func<T, object> CreateGet<T>(FieldInfo fieldInfo)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
if (!fieldInfo.IsStatic)
generator.PushInstance(fieldInfo.DeclaringType);
generator.Emit(OpCodes.Ldfld, fieldInfo);
generator.BoxIfNeeded(fieldInfo.FieldType);
generator.Emit(OpCodes.Ret);
return (Func<T, object>)
dynamicMethod.CreateDelegate(typeof(Func<T, object>));
}
public static Action<T, object> CreateSet<T>(FieldInfo fieldInfo)
{
DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(object), typeof(object) }, fieldInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
if (!fieldInfo.IsStatic)
generator.PushInstance(fieldInfo.DeclaringType);
generator.Emit(OpCodes.Ldarg_1);
generator.UnboxIfNeeded(fieldInfo.FieldType);
generator.Emit(OpCodes.Stfld, fieldInfo);
generator.Emit(OpCodes.Ret);
return (Action<T, object>)dynamicMethod.CreateDelegate(typeof(Action<T, object>));
}
public static Action<T, object> CreateSet<T>(PropertyInfo propertyInfo)
{
MethodInfo getMethod = propertyInfo.GetSetMethod(true);
DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
if (!getMethod.IsStatic)
generator.PushInstance(propertyInfo.DeclaringType);
generator.Emit(OpCodes.Ldarg_1);
generator.UnboxIfNeeded(propertyInfo.PropertyType);
if (getMethod.IsFinal || !getMethod.IsVirtual)
generator.Emit(OpCodes.Call, getMethod);
else
generator.Emit(OpCodes.Callvirt, getMethod);
generator.Emit(OpCodes.Ret);
return (Action<T, object>)dynamicMethod.CreateDelegate(typeof(Action<T, object>));
}
}
}
#endif
@@ -34,6 +34,8 @@ using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
internal delegate object MemberHandler<T>(T target, params object[] args);
internal static class ReflectionUtils
{
public static Type GetObjectType(object v)
@@ -76,7 +78,10 @@ namespace Newtonsoft.Json.Utilities
public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic)
{
BindingFlags accessModifier = (!nonPublic) ? BindingFlags.Public : BindingFlags.NonPublic;
BindingFlags accessModifier = BindingFlags.Public;
if (nonPublic)
accessModifier = accessModifier | BindingFlags.NonPublic;
return t.GetConstructor(accessModifier | BindingFlags.Instance, null, new Type[0], null);
}
@@ -187,7 +192,40 @@ namespace Newtonsoft.Json.Utilities
return false;
}
public static bool AssignableToTypeName(this Type type, string fullTypeName, out Type match)
{
Type current = type;
while (current != null)
{
if (current.FullName == fullTypeName)
{
match = current;
return true;
}
current = current.BaseType;
}
foreach (Type i in type.GetInterfaces())
{
if (i.Name == fullTypeName)
{
match = type;
return true;
}
}
match = null;
return false;
}
public static bool AssignableToTypeName(this Type type, string fullTypeName)
{
Type match;
return type.AssignableToTypeName(fullTypeName, out match);
}
public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition)
{
Type implementingType;
@@ -361,7 +399,7 @@ namespace Newtonsoft.Json.Utilities
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
default:
throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member");
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo or EventInfo", "member");
}
}
@@ -483,7 +521,7 @@ namespace Newtonsoft.Json.Utilities
switch (member.MemberType)
{
case MemberTypes.Field:
return true;
return !((FieldInfo)member).IsInitOnly;
case MemberTypes.Property:
return ((PropertyInfo)member).CanWrite;
default:
@@ -615,6 +653,9 @@ namespace Newtonsoft.Json.Utilities
#if !PocketPC
return Activator.CreateInstance(type, args);
#else
if (type.IsValueType)
return Activator.CreateInstance(type);
ConstructorInfo[] constructors = type.GetConstructors();
ConstructorInfo match = constructors.Where(c =>
{
@@ -635,7 +676,7 @@ namespace Newtonsoft.Json.Utilities
}).FirstOrDefault();
if (match == null)
throw new Exception("Could not create '{0}' with given parameters.".FormatWith(CultureInfo.InvariantCulture, args));
throw new Exception("Could not create '{0}' with given parameters.".FormatWith(CultureInfo.InvariantCulture, type));
return match.Invoke(args);
#endif