From 6d67aefac70fcc0a7648559deb784581ece305f5 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Wed, 17 Mar 2010 06:53:47 +0000 Subject: [PATCH] -Added ReflectionDelegateFactory, DynamicReflectionDelegateFactory and LateBoundDelegateFactory to support switching between dynamic and late bound reflection for medium trust environments -Added WriteObjectId to BsonWriter -Added BsonObjectId and BsonObjectIdConverter classes -Added KeyValuePairConverter -Added DynamicCodeGeneration flag to DefaultContractResolver -Changed JsonConverter.ReadJson to add an extra parameter: currentValue --- Build/build.ps1 | 6 + .../Bson/BsonWriterTests.cs | 51 ++++++ .../Converters/DataTableConverterTests.cs | 2 +- .../Converters/ObjectIdConverterTests.cs | 58 +++++++ .../Converters/XmlNodeConverterTest.cs | 4 +- .../LinqToSql/DepartmentConverter.cs | 2 +- .../LinqToSql/GuidByteArrayConverter.cs | 2 +- .../Newtonsoft.Json.Tests.Compact.csproj | 2 +- .../Newtonsoft.Json.Tests.Net20.csproj | 2 +- .../Newtonsoft.Json.Tests.Silverlight.csproj | 2 +- .../Newtonsoft.Json.Tests.csproj | 3 +- .../Serialization/JsonSerializerTest.cs | 157 +++++++++++++++++- .../PreserveReferencesHandlingTests.cs | 2 +- .../ConverterPrecedenceClassConverter.cs | 2 +- .../TestObjects/ListOfIds.cs | 2 +- ... DynamicReflectionDelegateFactoryTests.cs} | 10 +- Src/Newtonsoft.Json/Bson/BsonObjectId.cs | 47 ++++++ Src/Newtonsoft.Json/Bson/BsonWriter.cs | 33 +++- .../Converters/BinaryConverter.cs | 3 +- .../Converters/BsonObjectIdConverter.cs | 43 +++++ .../Converters/CustomCreationConverter.cs | 3 +- .../Converters/DataSetConverter.cs | 5 +- .../Converters/DataTableConverter.cs | 2 +- .../Converters/EntityKeyMemberConverter.cs | 3 +- .../Converters/HtmlColorConverter.cs | 3 +- .../Converters/IsoDateTimeConverter.cs | 3 +- .../Converters/JavaScriptDateTimeConverter.cs | 2 +- .../Converters/KeyValuePairConverter.cs | 51 ++++++ .../Converters/StringEnumConverter.cs | 3 +- .../Converters/XmlNodeConverter.cs | 3 +- Src/Newtonsoft.Json/JsonConverter.cs | 3 +- Src/Newtonsoft.Json/JsonWriter.cs | 5 +- Src/Newtonsoft.Json/Linq/JRaw.cs | 36 +--- Src/Newtonsoft.Json/Linq/JTokenWriter.cs | 2 +- Src/Newtonsoft.Json/Linq/JValue.cs | 2 +- .../Newtonsoft.Json.Compact.csproj | 11 +- .../Newtonsoft.Json.Net20.csproj | 11 +- .../Newtonsoft.Json.Silverlight.csproj | 11 +- Src/Newtonsoft.Json/Newtonsoft.Json.csproj | 11 +- .../Serialization/DefaultContractResolver.cs | 46 +++-- .../Serialization/DynamicValueProvider.cs | 4 +- .../Serialization/JsonArrayContract.cs | 8 +- .../Serialization/JsonDictionaryContract.cs | 8 +- .../JsonSerializerInternalReader.cs | 83 ++++++--- .../Serialization/JsonTypeReflector.cs | 45 ++++- .../LateBoundMetadataTypeAttribute.cs | 59 +++++++ ...cs => DynamicReflectionDelegateFactory.cs} | 104 +++--------- .../Utilities/ILGeneratorExtensions.cs | 77 +++++++++ .../LateBoundReflectionDelegateFactory.cs | 75 +++++++++ .../{MethodCaller.cs => MethodCall.cs} | 2 +- .../Utilities/ReflectionDelegateFactory.cs | 67 ++++++++ .../Utilities/ReflectionUtils.cs | 2 +- 52 files changed, 959 insertions(+), 224 deletions(-) create mode 100644 Src/Newtonsoft.Json.Tests/Converters/ObjectIdConverterTests.cs rename Src/Newtonsoft.Json.Tests/Utilities/{LateBoundDelegateFactoryTests.cs => DynamicReflectionDelegateFactoryTests.cs} (79%) create mode 100644 Src/Newtonsoft.Json/Bson/BsonObjectId.cs create mode 100644 Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs create mode 100644 Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs create mode 100644 Src/Newtonsoft.Json/Serialization/LateBoundMetadataTypeAttribute.cs rename Src/Newtonsoft.Json/Utilities/{LateBoundDelegateFactory.cs => DynamicReflectionDelegateFactory.cs} (66%) create mode 100644 Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs create mode 100644 Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs rename Src/Newtonsoft.Json/Utilities/{MethodCaller.cs => MethodCall.cs} (91%) create mode 100644 Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs diff --git a/Build/build.ps1 b/Build/build.ps1 index 44a2910c..cdc7dc35 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -21,6 +21,7 @@ task default -depends Test +# Ensure a clean working directory task Clean { Set-Location $baseDir @@ -34,6 +35,7 @@ task Clean { New-Item -Path $workingDir -ItemType Directory } +# Build each solution, optionally signed task Build -depends Clean { foreach ($build in $builds) @@ -47,6 +49,7 @@ task Build -depends Clean { } } +# Merge LinqBridge into .NET 2.0 build task Merge -depends Build { $binaryDir = "$sourceDir\Newtonsoft.Json\bin\Release\DotNet20" MergeAssembly "$binaryDir\Newtonsoft.Json.Net20.dll" $signKeyPath "$binaryDir\LinqBridge.dll" @@ -58,6 +61,7 @@ task Merge -depends Build { del $binaryDir\LinqBridge.dll } +# Optional build documentation, add files to final zip task Package -depends Merge { foreach ($build in $builds) { @@ -86,10 +90,12 @@ task Package -depends Merge { exec { .\Tools\7-zip\7za.exe a -tzip $workingDir\$zipFileName $workingDir\Package\* } "Error zipping" } +# Unzip package to a location task Deploy -depends Package { exec { .\Tools\7-zip\7za.exe x -y "-o$workingDir\Deployed" $workingDir\$zipFileName } "Error unzipping" } +# Run tests on deployed files task Test -depends Deploy { foreach ($build in $builds) { diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs index e97f5b0a..79307e2b 100644 --- a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs @@ -392,5 +392,56 @@ namespace Newtonsoft.Json.Tests.Bson Assert.AreEqual(9.95m, deserializedProduct.Price); Assert.AreEqual(3, deserializedProduct.Sizes.Length); } + + [Test] + public void WriteOid() + { + MemoryStream ms = new MemoryStream(); + BsonWriter writer = new BsonWriter(ms); + + byte[] oid = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + writer.WriteStartObject(); + writer.WritePropertyName("_oid"); + writer.WriteObjectId(oid); + writer.WriteEndObject(); + + string bson = MiscellaneousUtils.BytesToHex(ms.ToArray()); + Assert.AreEqual("17-00-00-00-07-5F-6F-69-64-00-01-02-03-04-05-06-07-08-09-0A-0B-0C-00", bson); + + ms.Seek(0, SeekOrigin.Begin); + BsonReader reader = new BsonReader(ms); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Bytes, reader.TokenType); + Assert.AreEqual(oid, reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + } + + [Test] + public void WriteOidPlusContent() + { + MemoryStream ms = new MemoryStream(); + BsonWriter writer = new BsonWriter(ms); + + writer.WriteStartObject(); + writer.WritePropertyName("_id"); + writer.WriteObjectId(MiscellaneousUtils.HexToBytes("4ABBED9D1D8B0F0218000001")); + writer.WritePropertyName("test"); + writer.WriteValue("1234£56"); + writer.WriteEndObject(); + + byte[] expected = MiscellaneousUtils.HexToBytes("29000000075F6964004ABBED9D1D8B0F02180000010274657374000900000031323334C2A335360000"); + + Assert.AreEqual(expected, ms.ToArray()); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs index e0b1f2fb..ffa3dcb7 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs @@ -111,7 +111,7 @@ namespace Newtonsoft.Json.Tests.Converters writer.WriteValue(d.TableName); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { //reader.Read(); DataTable d = new DataTable((string)reader.Value); diff --git a/Src/Newtonsoft.Json.Tests/Converters/ObjectIdConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/ObjectIdConverterTests.cs new file mode 100644 index 00000000..55600d26 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Converters/ObjectIdConverterTests.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Bson; +using Newtonsoft.Json.Tests.TestObjects; +using Newtonsoft.Json.Utilities; +using NUnit.Framework; + +namespace Newtonsoft.Json.Tests.Converters +{ + public class ObjectIdConverterTests : TestFixtureBase + { + public class ObjectIdTestClass + { + [JsonProperty("_id")] + public BsonObjectId Id { get; set; } + [JsonProperty("test")] + public string Test { get; set; } + } + + [Test] + public void Serialize() + { + ObjectIdTestClass c = new ObjectIdTestClass + { + Id = new BsonObjectId(MiscellaneousUtils.HexToBytes("4ABBED9D1D8B0F0218000001")), + Test = "1234£56" + }; + + MemoryStream ms = new MemoryStream(); + JsonSerializer serializer = new JsonSerializer(); + + // serialize product to BSON + BsonWriter writer = new BsonWriter(ms); + serializer.Serialize(writer, c); + + byte[] expected = MiscellaneousUtils.HexToBytes("29000000075F6964004ABBED9D1D8B0F02180000010274657374000900000031323334C2A335360000"); + + Assert.AreEqual(expected, ms.ToArray()); + } + + [Test] + public void Deserialize() + { + byte[] bson = MiscellaneousUtils.HexToBytes("29000000075F6964004ABBED9D1D8B0F02180000010274657374000900000031323334C2A335360000"); + + JsonSerializer serializer = new JsonSerializer(); + + BsonReader reader = new BsonReader(new MemoryStream(bson)); + ObjectIdTestClass c = serializer.Deserialize(reader); + + Assert.AreEqual(c.Id.Value, MiscellaneousUtils.HexToBytes("4ABBED9D1D8B0F0218000001")); + Assert.AreEqual(c.Test, "1234£56"); + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index f6b35fab..1865a17c 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -86,14 +86,14 @@ namespace Newtonsoft.Json.Tests.Converters if (deserializeRootElementName != null) converter.DeserializeRootElementName = deserializeRootElementName; - XmlNode node = (XmlNode)converter.ReadJson(reader, typeof (XmlDocument), new JsonSerializer()); + XmlNode node = (XmlNode)converter.ReadJson(reader, typeof (XmlDocument), null, new JsonSerializer()); #if !NET20 string xmlText = node.OuterXml; reader = new JsonTextReader(new StringReader(json)); reader.Read(); - XDocument d = (XDocument) converter.ReadJson(reader, typeof (XDocument), new JsonSerializer()); + XDocument d = (XDocument) converter.ReadJson(reader, typeof (XDocument), null, new JsonSerializer()); string linqXmlText = d.ToString(SaveOptions.DisableFormatting); if (d.Declaration != null) diff --git a/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs b/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs index a6adc942..b1ceb416 100644 --- a/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs +++ b/Src/Newtonsoft.Json.Tests/LinqToSql/DepartmentConverter.cs @@ -19,7 +19,7 @@ namespace Newtonsoft.Json.Tests.LinqToSql o.WriteTo(writer); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject o = JObject.Load(reader); diff --git a/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs b/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs index e6d4a5f2..82a1fdf1 100644 --- a/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs +++ b/Src/Newtonsoft.Json.Tests/LinqToSql/GuidByteArrayConverter.cs @@ -13,7 +13,7 @@ namespace Newtonsoft.Json.Tests.LinqToSql writer.WriteValue(Convert.ToBase64String(guid.ToByteArray())); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { string encodedData = (string) reader.Value; byte[] data = Convert.FromBase64String(encodedData); diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj index b579c2a0..7e2ea82e 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj @@ -198,7 +198,7 @@ - + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj index c84f0f75..7eb545e5 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj @@ -204,7 +204,7 @@ - + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index 5aaac287..638022d4 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -209,7 +209,7 @@ - + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 9ac9bd3b..e2d332d6 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -91,6 +91,7 @@ + True @@ -244,7 +245,7 @@ - + diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 1cde02d3..9e78a062 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -2983,7 +2983,7 @@ keyword such as type of business."" writer.WriteNull(); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } @@ -3006,7 +3006,7 @@ keyword such as type of business."" writer.WriteNull(); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } @@ -3056,5 +3056,158 @@ keyword such as type of business."" Assert.AreEqual(2, newValue.GenericList.Count); Assert.AreEqual(typeof(List), newValue.GenericList.GetType()); } + + [Test] + public void DeserializeSimpleKeyValuePair() + { + List> list = new List>(); + list.Add(new KeyValuePair("key1", "value1")); + list.Add(new KeyValuePair("key2", "value2")); + + string json = JsonConvert.SerializeObject(list); + + Assert.AreEqual(@"[{""Key"":""key1"",""Value"":""value1""},{""Key"":""key2"",""Value"":""value2""}]", json); + + List> result = JsonConvert.DeserializeObject>>(json); + Assert.AreEqual(2, result.Count); + Assert.AreEqual("key1", result[0].Key); + Assert.AreEqual("value1", result[0].Value); + Assert.AreEqual("key2", result[1].Key); + Assert.AreEqual("value2", result[1].Value); + } + + [Test] + public void DeserializeComplexKeyValuePair() + { + DateTime dateTime = new DateTime(2000, 12, 1, 23, 1, 1, DateTimeKind.Utc); + + List> list = new List>(); + list.Add(new KeyValuePair("key1", new WagePerson + { + BirthDate = dateTime, + Department = "Department1", + LastModified = dateTime, + HourlyWage = 1 + })); + list.Add(new KeyValuePair("key2", new WagePerson + { + BirthDate = dateTime, + Department = "Department2", + LastModified = dateTime, + HourlyWage = 2 + })); + + string json = JsonConvert.SerializeObject(list, Formatting.Indented); + + Assert.AreEqual(@"[ + { + ""Key"": ""key1"", + ""Value"": { + ""HourlyWage"": 1.0, + ""Name"": null, + ""BirthDate"": ""\/Date(975711661000)\/"", + ""LastModified"": ""\/Date(975711661000)\/"" + } + }, + { + ""Key"": ""key2"", + ""Value"": { + ""HourlyWage"": 2.0, + ""Name"": null, + ""BirthDate"": ""\/Date(975711661000)\/"", + ""LastModified"": ""\/Date(975711661000)\/"" + } + } +]", json); + + List> result = JsonConvert.DeserializeObject>>(json); + Assert.AreEqual(2, result.Count); + Assert.AreEqual("key1", result[0].Key); + Assert.AreEqual(1, result[0].Value.HourlyWage); + Assert.AreEqual("key2", result[1].Key); + Assert.AreEqual(2, result[1].Value.HourlyWage); + } + + public class StringListAppenderConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + List existingStrings = (List)existingValue; + List newStrings = new List(existingStrings); + + reader.Read(); + + while (reader.TokenType != JsonToken.EndArray) + { + string s = (string)reader.Value; + newStrings.Add(s); + + reader.Read(); + } + + return newStrings; + } + + public override bool CanConvert(Type objectType) + { + return (objectType == typeof (List)); + } + } + + [Test] + public void StringListAppenderConverterTest() + { + Movie p = new Movie(); + p.ReleaseCountries = new List { "Existing" }; + + JsonConvert.PopulateObject("{'ReleaseCountries':['Appended']}", p, new JsonSerializerSettings + { + Converters = new List { new StringListAppenderConverter() } + }); + + Assert.AreEqual(2, p.ReleaseCountries.Count); + Assert.AreEqual("Existing", p.ReleaseCountries[0]); + Assert.AreEqual("Appended", p.ReleaseCountries[1]); + } + + public class StringAppenderConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + string existingString = (string)existingValue; + string newString = existingString + (string)reader.Value; + + return newString; + } + + public override bool CanConvert(Type objectType) + { + return (objectType == typeof(string)); + } + } + + [Test] + public void StringAppenderConverterTest() + { + Movie p = new Movie(); + p.Name = "Existing,"; + + JsonConvert.PopulateObject("{'Name':'Appended'}", p, new JsonSerializerSettings + { + Converters = new List { new StringAppenderConverter() } + }); + + Assert.AreEqual(p.Name, "Existing,Appended"); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs index c625e6c4..d0b10835 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs @@ -296,7 +296,7 @@ namespace Newtonsoft.Json.Tests.Serialization me.WriteTo(writer); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject o = JObject.Load(reader); string id = (string)o["$id"]; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs index f22f27de..6590ee9f 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConverterPrecedenceClassConverter.cs @@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Tests.TestObjects j.WriteTo(writer); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken j = JArray.Load(reader); diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs index 617f229c..7d0ccc3b 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs @@ -42,7 +42,7 @@ namespace Newtonsoft.Json.Tests.TestObjects writer.WriteEndArray(); } - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { IList list = new List(); diff --git a/Src/Newtonsoft.Json.Tests/Utilities/LateBoundDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs similarity index 79% rename from Src/Newtonsoft.Json.Tests/Utilities/LateBoundDelegateFactoryTests.cs rename to Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs index 53090655..bbe80e0c 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/LateBoundDelegateFactoryTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs @@ -34,7 +34,7 @@ using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Utilities { - public class LateBoundDelegateFactoryTests : TestFixtureBase + public class DynamicReflectionDelegateFactoryTests : TestFixtureBase { [Test] [ExpectedException(typeof(InvalidCastException), ExpectedMessage = "Unable to cast object of type 'Newtonsoft.Json.Tests.TestObjects.Person' to type 'Newtonsoft.Json.Tests.TestObjects.Movie'.")] @@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Tests.Utilities Person p = new Person(); p.Name = "Hi"; - Func setter = LateBoundDelegateFactory.CreateGet(typeof(Movie).GetProperty("Name")); + Func setter = DynamicReflectionDelegateFactory.Instance.CreateGet(typeof(Movie).GetProperty("Name")); setter(p); } @@ -55,7 +55,7 @@ namespace Newtonsoft.Json.Tests.Utilities Person p = new Person(); Movie m = new Movie(); - Action setter = LateBoundDelegateFactory.CreateSet(typeof(Movie).GetProperty("Name")); + Action setter = DynamicReflectionDelegateFactory.Instance.CreateSet(typeof(Movie).GetProperty("Name")); setter(m, "Hi"); @@ -70,7 +70,7 @@ namespace Newtonsoft.Json.Tests.Utilities { object structTest = new StructTest(); - Action setter = LateBoundDelegateFactory.CreateSet(typeof(StructTest).GetProperty("StringProperty")); + Action setter = DynamicReflectionDelegateFactory.Instance.CreateSet(typeof(StructTest).GetProperty("StringProperty")); setter(structTest, "Hi"); @@ -85,7 +85,7 @@ namespace Newtonsoft.Json.Tests.Utilities { Movie m = new Movie(); - Action setter = LateBoundDelegateFactory.CreateSet(typeof(Movie).GetProperty("Name")); + Action setter = DynamicReflectionDelegateFactory.Instance.CreateSet(typeof(Movie).GetProperty("Name")); setter(m, new Version()); } diff --git a/Src/Newtonsoft.Json/Bson/BsonObjectId.cs b/Src/Newtonsoft.Json/Bson/BsonObjectId.cs new file mode 100644 index 00000000..5a305ad8 --- /dev/null +++ b/Src/Newtonsoft.Json/Bson/BsonObjectId.cs @@ -0,0 +1,47 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Bson +{ + public class BsonObjectId + { + public byte[] Value { get; private set; } + + public BsonObjectId(byte[] value) + { + ValidationUtils.ArgumentNotNull(value, "value"); + if (value.Length != 12) + throw new Exception("An ObjectId must be 12 bytes"); + + Value = value; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Bson/BsonWriter.cs b/Src/Newtonsoft.Json/Bson/BsonWriter.cs index 1d7bc0c7..7fa0808a 100644 --- a/Src/Newtonsoft.Json/Bson/BsonWriter.cs +++ b/Src/Newtonsoft.Json/Bson/BsonWriter.cs @@ -110,7 +110,7 @@ namespace Newtonsoft.Json.Bson case JTokenType.Undefined: break; case JTokenType.Date: - DateTime dateTime = (DateTime) t; + DateTime dateTime = (DateTime)t; dateTime = dateTime.ToUniversalTime(); long ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime); _writer.Write(ticks); @@ -121,6 +121,11 @@ namespace Newtonsoft.Json.Bson _writer.Write((byte)BsonBinaryType.Data); _writer.Write(data); break; + case JTokenType.Raw: + // hacky + JRaw r = (JRaw)t; + _writer.Write((byte[])r.Value); + break; default: throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type)); } @@ -182,6 +187,9 @@ namespace Newtonsoft.Json.Bson return BsonType.Date; case JTokenType.Bytes: return BsonType.Binary; + case JTokenType.Raw: + // hacky + return BsonType.Oid; default: throw new ArgumentOutOfRangeException("t", "Unexpected token when resolving JSON type to BSON type: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type)); } @@ -235,7 +243,7 @@ namespace Newtonsoft.Json.Bson return bases; } case JTokenType.Property: - JProperty property = (JProperty) t; + JProperty property = (JProperty)t; int ss = 1; ss += CalculateSize(property.Name); ss += CalculateSize(property.Value); @@ -256,8 +264,11 @@ namespace Newtonsoft.Json.Bson case JTokenType.Date: return 8; case JTokenType.Bytes: - byte[] data = (byte[]) t; + byte[] data = (byte[])t; return 4 + 1 + data.Length; + case JTokenType.Raw: + // hacky + return 12; default: throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type)); } @@ -312,5 +323,21 @@ namespace Newtonsoft.Json.Bson { throw new JsonWriterException("Cannot write raw JSON as BSON."); } + + /// + /// Writes a value that represents a BSON object id. + /// + /// + public void WriteObjectId(byte[] value) + { + ValidationUtils.ArgumentNotNull(value, "value"); + + if (value.Length != 12) + throw new Exception("An object id must be 12 bytes"); + + // hack to update the writer state + AutoComplete(JsonToken.Undefined); + AddValue(new JRaw(value), JsonToken.Raw); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs index 6b039448..c92c6f7c 100644 --- a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs +++ b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs @@ -88,9 +88,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { Type t = (ReflectionUtils.IsNullableType(objectType)) ? Nullable.GetUnderlyingType(objectType) diff --git a/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs b/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs new file mode 100644 index 00000000..2d0ef82c --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Bson; +using System.Globalization; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Converters +{ + public class BsonObjectIdConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + BsonObjectId objectId = (BsonObjectId) value; + + BsonWriter bsonWriter = writer as BsonWriter; + if (bsonWriter != null) + { + bsonWriter.WriteObjectId(objectId.Value); + } + else + { + writer.WriteValue(objectId.Value); + } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType != JsonToken.Bytes) + throw new JsonSerializationException("Expected Bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); + + byte[] value = (byte[])reader.Value; + + return new BsonObjectId(value); + } + + public override bool CanConvert(Type objectType) + { + return (objectType == typeof (BsonObjectId)); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs b/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs index e20fbfc9..ecd8e618 100644 --- a/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs +++ b/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs @@ -49,9 +49,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { T value = Create(objectType); if (value == null) diff --git a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs index 24088cc2..ef4e8726 100644 --- a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs @@ -63,9 +63,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { DataSet ds = new DataSet(); @@ -75,7 +76,7 @@ namespace Newtonsoft.Json.Converters while (reader.TokenType == JsonToken.PropertyName) { - DataTable dt = (DataTable)converter.ReadJson(reader, typeof (DataTable), serializer); + DataTable dt = (DataTable)converter.ReadJson(reader, typeof (DataTable), null, serializer); ds.Tables.Add(dt); } diff --git a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs index 06117ac3..3f588df6 100644 --- a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs @@ -67,7 +67,7 @@ namespace Newtonsoft.Json.Converters /// Type of the object. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { DataTable dt; diff --git a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs index e47e5c11..6dfc2878 100644 --- a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs +++ b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs @@ -98,9 +98,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { IEntityKeyMember entityKeyMember = DynamicWrapper.CreateWrapper(Activator.CreateInstance(objectType)); diff --git a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs index 5ae24f8b..137c24ab 100644 --- a/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs +++ b/Src/Newtonsoft.Json/Converters/HtmlColorConverter.cs @@ -62,9 +62,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs index 5150c441..2a2dac80 100644 --- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs @@ -89,9 +89,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { bool nullable = ReflectionUtils.IsNullableType(objectType); Type t = (nullable) diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index 130f63e6..323e85b1 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -50,7 +50,7 @@ namespace Newtonsoft.Json.Converters /// Type of the object. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { Type t = (ReflectionUtils.IsNullableType(objectType)) ? Nullable.GetUnderlyingType(objectType) diff --git a/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs b/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs new file mode 100644 index 00000000..58e22db1 --- /dev/null +++ b/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Utilities; +using System.Reflection; + +namespace Newtonsoft.Json.Converters +{ + public class KeyValuePairConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + Type t = value.GetType(); + PropertyInfo keyProperty = t.GetProperty("Key"); + PropertyInfo valueProperty = t.GetProperty("Value"); + + writer.WriteStartObject(); + writer.WritePropertyName("Key"); + serializer.Serialize(writer, ReflectionUtils.GetMemberValue(keyProperty, value)); + writer.WritePropertyName("Value"); + serializer.Serialize(writer, ReflectionUtils.GetMemberValue(valueProperty, value)); + writer.WriteEndObject(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + IList genericArguments = objectType.GetGenericArguments(); + Type keyType = genericArguments[0]; + Type valueType = genericArguments[1]; + + reader.Read(); + reader.Read(); + object key = serializer.Deserialize(reader, keyType); + reader.Read(); + reader.Read(); + object value = serializer.Deserialize(reader, valueType); + reader.Read(); + + return ReflectionUtils.CreateInstance(objectType, key, value); + } + + public override bool CanConvert(Type objectType) + { + if (objectType.IsValueType && objectType.IsGenericType) + return (objectType.GetGenericTypeDefinition() == typeof (KeyValuePair<,>)); + + return false; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs index 19b739c9..a2996971 100644 --- a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs +++ b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs @@ -63,9 +63,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { Type t = (ReflectionUtils.IsNullableType(objectType)) ? Nullable.GetUnderlyingType(objectType) diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 57277577..c73050c1 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -1016,9 +1016,10 @@ namespace Newtonsoft.Json.Converters /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable()); IXmlDocument document; diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs index 493e2525..1597a44f 100644 --- a/Src/Newtonsoft.Json/JsonConverter.cs +++ b/Src/Newtonsoft.Json/JsonConverter.cs @@ -49,9 +49,10 @@ namespace Newtonsoft.Json /// /// The to read from. /// Type of the object. + /// The existing value of object being read. /// The calling serializer. /// The object value. - public abstract object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer); + public abstract object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer); /// /// Determines whether this instance can convert the specified object type. diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 3b5b9884..2a18d29a 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -373,6 +373,9 @@ namespace Newtonsoft.Json case JsonToken.Raw: WriteRawValue((string)reader.Value); break; + case JsonToken.Bytes: + WriteValue((byte[])reader.Value); + break; default: throw MiscellaneousUtils.CreateArgumentOutOfRangeException("TokenType", reader.TokenType, "Unexpected token type."); } @@ -563,7 +566,7 @@ namespace Newtonsoft.Json { } - private void AutoComplete(JsonToken tokenBeingWritten) + internal void AutoComplete(JsonToken tokenBeingWritten) { int token; diff --git a/Src/Newtonsoft.Json/Linq/JRaw.cs b/Src/Newtonsoft.Json/Linq/JRaw.cs index a6db8f61..7e24713e 100644 --- a/Src/Newtonsoft.Json/Linq/JRaw.cs +++ b/Src/Newtonsoft.Json/Linq/JRaw.cs @@ -25,7 +25,7 @@ namespace Newtonsoft.Json.Linq /// Initializes a new instance of the class. /// /// The raw json. - public JRaw(string rawJson) + public JRaw(object rawJson) : base(rawJson, JTokenType.Raw) { } @@ -50,39 +50,5 @@ namespace Newtonsoft.Json.Linq { return new JRaw(this); } - - //public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) - //{ - // writer.WriteRawValue(Value); - //} - - //internal override JToken CloneToken() - //{ - // throw new NotImplementedException(); - //} - - //internal override bool DeepEquals(JToken node) - //{ - // JRaw other = node as JRaw; - // if (other == null) - // return false; - - // return (this == other || string.Equals(Value, other.Value, StringComparison.Ordinal)); - //} - - //public override JTokenType Type - //{ - // get { return JTokenType.Raw; } - //} - - //public override bool HasValues - //{ - // get { return false; } - //} - - //internal override int GetDeepHashCode() - //{ - // return Value.GetHashCode(); - //} } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs index ddb68b9a..a8258c34 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs @@ -139,7 +139,7 @@ namespace Newtonsoft.Json.Linq AddValue(new JValue(value), token); } - private void AddValue(JValue value, JsonToken token) + internal void AddValue(JValue value, JsonToken token) { if (_parent != null) { diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 8df6dd95..3150345c 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -315,7 +315,7 @@ namespace Newtonsoft.Json.Linq }, _value); break; case JTokenType.Raw: - writer.WriteRawValue((string)_value); + writer.WriteRawValue((_value != null) ? _value.ToString() : null); break; case JTokenType.Bytes: WriteConvertableValue(writer, converters, v => writer.WriteValue((byte[])v), _value); diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj index b748d2c7..fa2ebc75 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj @@ -58,16 +58,19 @@ + + + @@ -164,6 +167,7 @@ + @@ -175,20 +179,23 @@ + + - + - + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index 4335ec51..204dadd4 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -78,16 +78,19 @@ + + + @@ -183,13 +186,17 @@ + + - - + + + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index d0f4aaa3..2b11fe39 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -55,11 +55,13 @@ + + @@ -68,6 +70,7 @@ + @@ -147,6 +150,7 @@ + @@ -159,16 +163,19 @@ + + - + - + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 458e9587..7b27b53a 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -84,12 +84,15 @@ + + + @@ -186,13 +189,17 @@ + - + - + + + + diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 03097ee2..472b7bb9 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -31,6 +31,7 @@ using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.Serialization; +using System.Security.Permissions; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Linq; @@ -79,11 +80,13 @@ namespace Newtonsoft.Json.Serialization new EntityKeyMemberConverter(), #endif new BinaryConverter(), + new KeyValuePairConverter(), #if !SILVERLIGHT new XmlNodeConverter(), new DataSetConverter(), - new DataTableConverter() + new DataTableConverter(), #endif + new BsonObjectIdConverter() }; private static Dictionary _sharedContractCache; @@ -92,6 +95,18 @@ namespace Newtonsoft.Json.Serialization private Dictionary _instanceContractCache; private readonly bool _sharedCache; + /// + /// Gets a value indicating whether members are being get and set using dynamic code generation. + /// This value is determined by the runtime permissions available. + /// + /// + /// true if using dynamic code generation; otherwise, false. + /// + public bool DynamicCodeGeneration + { + get { return JsonTypeReflector.DynamicCodeGeneration; } + } + /// /// Gets or sets the default members search flags. /// @@ -267,6 +282,11 @@ namespace Newtonsoft.Json.Serialization return JsonTypeReflector.GetJsonConverter(objectType, objectType); } + private Func GetDefaultCreator(Type createdType) + { + return JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(createdType); + } + private void InitializeContract(JsonContract contract) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetJsonContainerAttribute(contract.UnderlyingType); @@ -292,19 +312,8 @@ namespace Newtonsoft.Json.Serialization if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true) || contract.CreatedType.IsValueType) { -#if !PocketPC && !SILVERLIGHT - contract.DefaultCreator = LateBoundDelegateFactory.CreateDefaultConstructor(contract.CreatedType); -#else - ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(contract.CreatedType, true); + contract.DefaultCreator = GetDefaultCreator(contract.CreatedType); - 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); } @@ -410,9 +419,9 @@ namespace Newtonsoft.Json.Serialization ConstructorInfo constructorInfo = objectType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new [] {typeof (SerializationInfo), typeof (StreamingContext)}, null); if (constructorInfo != null) { - MethodCaller methodCaller = LateBoundDelegateFactory.CreateMethodCall(constructorInfo); + MethodCall methodCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(constructorInfo); - contract.ISerializableCreator = (args => methodCaller(null, args)); + contract.ISerializableCreator = (args => methodCall(null, args)); } return contract; @@ -572,10 +581,11 @@ namespace Newtonsoft.Json.Serialization protected virtual IValueProvider CreateMemberValueProvider(MemberInfo member) { #if !PocketPC && !SILVERLIGHT - return new DynamicValueProvider(member); -#else - return new ReflectionValueProvider(member); + if (DynamicCodeGeneration) + return new DynamicValueProvider(member); #endif + + return new ReflectionValueProvider(member); } /// diff --git a/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs b/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs index 41736ed5..ec302bbb 100644 --- a/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs +++ b/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs @@ -63,7 +63,7 @@ namespace Newtonsoft.Json.Serialization try { if (_setter == null) - _setter = LateBoundDelegateFactory.CreateSet(_memberInfo); + _setter = DynamicReflectionDelegateFactory.Instance.CreateSet(_memberInfo); #if DEBUG // dynamic method doesn't check whether the type is 'legal' to set @@ -97,7 +97,7 @@ namespace Newtonsoft.Json.Serialization try { if (_getter == null) - _getter = LateBoundDelegateFactory.CreateGet(_memberInfo); + _getter = DynamicReflectionDelegateFactory.Instance.CreateGet(_memberInfo); return _getter(target); } diff --git a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs index d7ddc162..19545822 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs @@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Serialization private bool _isCollectionItemTypeNullableType; private Type _genericCollectionDefinitionType; private Type _genericWrapperType; - private MethodCaller _genericWrapperCreator; + private MethodCall _genericWrapperCreator; /// /// Initializes a new instance of the class. @@ -78,11 +78,7 @@ namespace Newtonsoft.Json.Serialization _genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType); ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType }); -#if !PocketPC && !SILVERLIGHT - _genericWrapperCreator = LateBoundDelegateFactory.CreateMethodCall(genericWrapperConstructor); -#else - _genericWrapperCreator = (target, args) => genericWrapperConstructor.Invoke(new[] { args[0] }); -#endif + _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor); } return (IWrappedCollection)_genericWrapperCreator(null, list); diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs index cc8fc570..03fdbe3b 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs @@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Serialization private readonly Type _genericCollectionDefinitionType; private Type _genericWrapperType; - private MethodCaller _genericWrapperCreator; + private MethodCall _genericWrapperCreator; /// /// Initializes a new instance of the class. @@ -81,11 +81,7 @@ namespace Newtonsoft.Json.Serialization _genericWrapperType = ReflectionUtils.MakeGenericType(typeof(DictionaryWrapper<,>), DictionaryKeyType, DictionaryValueType); ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType }); -#if !PocketPC && !SILVERLIGHT - _genericWrapperCreator = LateBoundDelegateFactory.CreateMethodCall(genericWrapperConstructor); -#else - _genericWrapperCreator = (target, args) => genericWrapperConstructor.Invoke(new[] { args[0] }); -#endif + _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor); } return (IWrappedDictionary)_genericWrapperCreator(null, dictionary); diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 71320153..740122ad 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -114,7 +114,7 @@ namespace Newtonsoft.Json.Serialization if (reader.TokenType == JsonToken.None && !reader.Read()) return null; - return CreateValue(reader, objectType, GetContractSafe(objectType), null, null); + return CreateValueNonProperty(reader, objectType, GetContractSafe(objectType)); } private JsonSerializerProxy GetInternalSerializer() @@ -177,31 +177,36 @@ namespace Newtonsoft.Json.Serialization return token; } - private object CreateValue(JsonReader reader, Type objectType, JsonContract contract, object existingValue, JsonConverter memberConverter) + private object CreateValueProperty(JsonReader reader, JsonProperty property, object target, bool gottenCurrentValue, object currentValue) { - JsonConverter converter = null; - if (memberConverter != null) - { - // member attribute converter - converter = memberConverter; - } - else if (contract != null) - { - JsonConverter matchingConverter; - if (contract.Converter != null) - // class attribute converter - converter = contract.Converter; - else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null) - // passed in converters - converter = matchingConverter; - else if (contract.InternalConverter != null) - // internally specified converter - converter = contract.InternalConverter; - } + JsonContract contract = GetContractSafe(property.PropertyType, currentValue); + Type objectType = property.PropertyType; + + JsonConverter converter = GetConverter(contract, property.MemberConverter); if (converter != null && converter.CanRead) - return converter.ReadJson(reader, objectType, GetInternalSerializer()); + { + if (!gottenCurrentValue && target != null && property.Readable) + currentValue = property.ValueProvider.GetValue(target); + return converter.ReadJson(reader, objectType, currentValue, GetInternalSerializer()); + } + + return CreateValueInternal(reader, objectType, contract, currentValue); + } + + private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract) + { + JsonConverter converter = GetConverter(contract, null); + + if (converter != null && converter.CanRead) + return converter.ReadJson(reader, objectType, null, GetInternalSerializer()); + + return CreateValueInternal(reader, objectType, contract, null); + } + + private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, object existingValue) + { if (contract is JsonLinqContract) return CreateJToken(reader, contract); @@ -253,6 +258,30 @@ namespace Newtonsoft.Json.Serialization throw new JsonSerializationException("Unexpected end when deserializing object."); } + private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter) + { + JsonConverter converter = null; + if (memberConverter != null) + { + // member attribute converter + converter = memberConverter; + } + else if (contract != null) + { + JsonConverter matchingConverter; + if (contract.Converter != null) + // class attribute converter + converter = contract.Converter; + else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null) + // passed in converters + converter = matchingConverter; + else if (contract.InternalConverter != null) + // internally specified converter + converter = contract.InternalConverter; + } + return converter; + } + private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, object existingValue) { CheckedRead(reader); @@ -454,6 +483,7 @@ namespace Newtonsoft.Json.Serialization object currentValue = null; bool useExistingValue = false; + bool gottenCurrentValue = false; ObjectCreationHandling objectCreationHandling = property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling); @@ -463,6 +493,7 @@ namespace Newtonsoft.Json.Serialization && property.Readable) { currentValue = property.ValueProvider.GetValue(target); + gottenCurrentValue = true; useExistingValue = (currentValue != null && !property.PropertyType.IsArray && !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof(ReadOnlyCollection<>))); } @@ -474,7 +505,7 @@ namespace Newtonsoft.Json.Serialization } object existingValue = (useExistingValue) ? currentValue : null; - object value = CreateValue(reader, property.PropertyType, GetContractSafe(property.PropertyType, existingValue), existingValue, property.Converter); + object value = CreateValueProperty(reader, property, target, gottenCurrentValue, existingValue); // always set the value if useExistingValue is false, // otherwise also set it if CreateValue returns a new value compared to the currentValue @@ -543,7 +574,7 @@ namespace Newtonsoft.Json.Serialization try { - dictionary[keyValue] = CreateValue(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType), null, null); + dictionary[keyValue] = CreateValueNonProperty(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType)); } catch (Exception ex) { @@ -607,7 +638,7 @@ namespace Newtonsoft.Json.Serialization default: try { - object value = CreateValue(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType), null, null); + object value = CreateValueNonProperty(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType)); wrappedList.Add(value); } @@ -717,7 +748,7 @@ namespace Newtonsoft.Json.Serialization { if (!property.Ignored) { - propertyValues[property] = CreateValue(reader, property.PropertyType, GetContractSafe(property.PropertyType), null, property.MemberConverter); + propertyValues[property] = CreateValueProperty(reader, property, null, true, null); } } else diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs index dceed5bf..45263587 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs @@ -29,6 +29,7 @@ using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.Serialization; +using System.Security.Permissions; using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Serialization @@ -176,7 +177,9 @@ namespace Newtonsoft.Json.Serialization if (attribute == null) return null; - IMetadataTypeAttribute metadataTypeAttribute = DynamicWrapper.CreateWrapper(attribute); + IMetadataTypeAttribute metadataTypeAttribute = (DynamicCodeGeneration) + ? DynamicWrapper.CreateWrapper(attribute) + : new LateBoundMetadataTypeAttribute(attribute); return metadataTypeAttribute.MetadataClassType; } @@ -249,5 +252,45 @@ namespace Newtonsoft.Json.Serialization return ReflectionUtils.GetAttribute(attributeProvider, true); } #endif + + private static bool? _dynamicCodeGeneration; + + public static bool DynamicCodeGeneration + { + get + { + if (_dynamicCodeGeneration == null) + { +#if !PocketPC && !SILVERLIGHT + try + { + new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand(); + _dynamicCodeGeneration = true; + } + catch (Exception) + { + _dynamicCodeGeneration = false; + } +#else + _dynamicCodeGeneration = false; +#endif + } + + return _dynamicCodeGeneration.Value; + } + } + + public static ReflectionDelegateFactory ReflectionDelegateFactory + { + get + { +#if !PocketPC && !SILVERLIGHT + if (DynamicCodeGeneration) + return DynamicReflectionDelegateFactory.Instance; +#endif + + return LateBoundReflectionDelegateFactory.Instance; + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/LateBoundMetadataTypeAttribute.cs b/Src/Newtonsoft.Json/Serialization/LateBoundMetadataTypeAttribute.cs new file mode 100644 index 00000000..815f20be --- /dev/null +++ b/Src/Newtonsoft.Json/Serialization/LateBoundMetadataTypeAttribute.cs @@ -0,0 +1,59 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !SILVERLIGHT && !PocketPC && !NET20 +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Utilities; +using System.Reflection; + +namespace Newtonsoft.Json.Serialization +{ + internal class LateBoundMetadataTypeAttribute : IMetadataTypeAttribute + { + private static PropertyInfo _metadataClassTypeProperty; + + private readonly object _attribute; + + public LateBoundMetadataTypeAttribute(object attribute) + { + _attribute = attribute; + } + + public Type MetadataClassType + { + get + { + if (_metadataClassTypeProperty == null) + _metadataClassTypeProperty = _attribute.GetType().GetProperty("MetadataClassType"); + + return (Type)ReflectionUtils.GetMemberValue(_metadataClassTypeProperty, _attribute); + } + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/LateBoundDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs similarity index 66% rename from Src/Newtonsoft.Json/Utilities/LateBoundDelegateFactory.cs rename to Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs index e4601148..d1effde7 100644 --- a/Src/Newtonsoft.Json/Utilities/LateBoundDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs @@ -34,20 +34,9 @@ using System.Globalization; namespace Newtonsoft.Json.Utilities { - internal static class LateBoundDelegateFactory + internal class DynamicReflectionDelegateFactory : ReflectionDelegateFactory { - public static Func CreateGet(MemberInfo memberInfo) - { - PropertyInfo propertyInfo = memberInfo as PropertyInfo; - if (propertyInfo != null) - return CreateGet(propertyInfo); - - FieldInfo fieldInfo = memberInfo as FieldInfo; - if (fieldInfo != null) - return CreateGet(fieldInfo); - - throw new Exception("Could not create getter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); - } + public static DynamicReflectionDelegateFactory Instance = new DynamicReflectionDelegateFactory(); private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner) { @@ -58,20 +47,7 @@ namespace Newtonsoft.Json.Utilities return dynamicMethod; } - public static Action CreateSet(MemberInfo memberInfo) - { - PropertyInfo propertyInfo = memberInfo as PropertyInfo; - if (propertyInfo != null) - return CreateSet(propertyInfo); - - FieldInfo fieldInfo = memberInfo as FieldInfo; - if (fieldInfo != null) - return CreateSet(fieldInfo); - - throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); - } - - public static MethodCaller CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType); ILGenerator generator = dynamicMethod.GetILGenerator(); @@ -105,9 +81,7 @@ namespace Newtonsoft.Json.Utilities 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); + generator.CallMethod((MethodInfo)method); Type returnType = method.IsConstructor ? method.DeclaringType @@ -118,13 +92,12 @@ namespace Newtonsoft.Json.Utilities else generator.Emit(OpCodes.Ldnull); - generator.Emit(OpCodes.Ret); + generator.Return(); - return (MethodCaller)dynamicMethod.CreateDelegate(typeof(MethodCaller)); + return (MethodCall)dynamicMethod.CreateDelegate(typeof(MethodCall)); } - - public static Func CreateDefaultConstructor(Type type) + public override Func CreateDefaultConstructor(Type type) { DynamicMethod dynamicMethod = CreateDynamicMethod("Create" + type.FullName, typeof(object), Type.EmptyTypes, type); dynamicMethod.InitLocals = true; @@ -148,12 +121,12 @@ namespace Newtonsoft.Json.Utilities generator.Emit(OpCodes.Newobj, constructorInfo); } - generator.Emit(OpCodes.Ret); + generator.Return(); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } - public static Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { MethodInfo getMethod = propertyInfo.GetGetMethod(true); if (getMethod == null) @@ -167,43 +140,14 @@ namespace Newtonsoft.Json.Utilities if (!getMethod.IsStatic) generator.PushInstance(propertyInfo.DeclaringType); - if (getMethod.IsFinal || !getMethod.IsVirtual) - generator.Emit(OpCodes.Call, getMethod); - else - generator.Emit(OpCodes.Callvirt, getMethod); - + generator.CallMethod(getMethod); generator.BoxIfNeeded(propertyInfo.PropertyType); - generator.Emit(OpCodes.Ret); + generator.Return(); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } - static void PushInstance(this ILGenerator generator, Type type) - { - generator.Emit(OpCodes.Ldarg_0); - if (type.IsValueType) - generator.Emit(OpCodes.Unbox, type); - else - generator.Emit(OpCodes.Castclass, type); - } - - static void BoxIfNeeded(this ILGenerator generator, Type type) - { - if (type.IsValueType) - generator.Emit(OpCodes.Box, type); - else - generator.Emit(OpCodes.Castclass, type); - } - - static void UnboxIfNeeded(this ILGenerator generator, Type type) - { - if (type.IsValueType) - generator.Emit(OpCodes.Unbox_Any, type); - else - generator.Emit(OpCodes.Castclass, type); - } - - public static Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType); @@ -214,13 +158,12 @@ namespace Newtonsoft.Json.Utilities generator.Emit(OpCodes.Ldfld, fieldInfo); generator.BoxIfNeeded(fieldInfo.FieldType); - generator.Emit(OpCodes.Ret); + generator.Return(); - return (Func) - dynamicMethod.CreateDelegate(typeof(Func)); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } - public static Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(object), typeof(object) }, fieldInfo.DeclaringType); ILGenerator generator = dynamicMethod.GetILGenerator(); @@ -231,29 +174,24 @@ namespace Newtonsoft.Json.Utilities generator.Emit(OpCodes.Ldarg_1); generator.UnboxIfNeeded(fieldInfo.FieldType); generator.Emit(OpCodes.Stfld, fieldInfo); - generator.Emit(OpCodes.Ret); + generator.Return(); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } - public static Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { - MethodInfo getMethod = propertyInfo.GetSetMethod(true); + MethodInfo setMethod = propertyInfo.GetSetMethod(true); DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType); ILGenerator generator = dynamicMethod.GetILGenerator(); - if (!getMethod.IsStatic) + if (!setMethod.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); + generator.CallMethod(setMethod); + generator.Return(); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } diff --git a/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs b/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs new file mode 100644 index 00000000..29bd3a22 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs @@ -0,0 +1,77 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !PocketPC && !SILVERLIGHT +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using System.Reflection; + +namespace Newtonsoft.Json.Utilities +{ + public static class ILGeneratorExtensions + { + public static void PushInstance(this ILGenerator generator, Type type) + { + generator.Emit(OpCodes.Ldarg_0); + if (type.IsValueType) + generator.Emit(OpCodes.Unbox, type); + else + generator.Emit(OpCodes.Castclass, type); + } + + public static void BoxIfNeeded(this ILGenerator generator, Type type) + { + if (type.IsValueType) + generator.Emit(OpCodes.Box, type); + else + generator.Emit(OpCodes.Castclass, type); + } + + public static void UnboxIfNeeded(this ILGenerator generator, Type type) + { + if (type.IsValueType) + generator.Emit(OpCodes.Unbox_Any, type); + else + generator.Emit(OpCodes.Castclass, type); + } + + public static void CallMethod(this ILGenerator generator, MethodInfo methodInfo) + { + if (methodInfo.IsFinal || !methodInfo.IsVirtual) + generator.Emit(OpCodes.Call, methodInfo); + else + generator.Emit(OpCodes.Callvirt, methodInfo); + } + + public static void Return(this ILGenerator generator) + { + generator.Emit(OpCodes.Ret); + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs new file mode 100644 index 00000000..9f964317 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs @@ -0,0 +1,75 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Globalization; +using System.Reflection; + +namespace Newtonsoft.Json.Utilities +{ + internal class LateBoundReflectionDelegateFactory : ReflectionDelegateFactory + { + public static readonly LateBoundReflectionDelegateFactory Instance = new LateBoundReflectionDelegateFactory(); + + public override MethodCall CreateMethodCall(MethodBase method) + { + ConstructorInfo c = method as ConstructorInfo; + if (c != null) + return (o, a) => c.Invoke(a); + + return (o, a) => method.Invoke(o, a); + } + + public override Func CreateDefaultConstructor(Type type) + { + if (type.IsValueType) + return () => ReflectionUtils.CreateInstance(type); + + ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true); + + return () => constructorInfo.Invoke(null); + } + + public override Func CreateGet(PropertyInfo propertyInfo) + { + return o => propertyInfo.GetValue(o, null); + } + + public override Func CreateGet(FieldInfo fieldInfo) + { + return o => fieldInfo.GetValue(o); + } + + public override Action CreateSet(FieldInfo fieldInfo) + { + return (o, v) => fieldInfo.SetValue(o, v); + } + + public override Action CreateSet(PropertyInfo propertyInfo) + { + return (o, v) => propertyInfo.SetValue(o, v, null); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/MethodCaller.cs b/Src/Newtonsoft.Json/Utilities/MethodCall.cs similarity index 91% rename from Src/Newtonsoft.Json/Utilities/MethodCaller.cs rename to Src/Newtonsoft.Json/Utilities/MethodCall.cs index e588d126..efbc8175 100644 --- a/Src/Newtonsoft.Json/Utilities/MethodCaller.cs +++ b/Src/Newtonsoft.Json/Utilities/MethodCall.cs @@ -25,5 +25,5 @@ namespace Newtonsoft.Json.Utilities { - internal delegate object MethodCaller(T target, params object[] args); + internal delegate object MethodCall(T target, params object[] args); } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs new file mode 100644 index 00000000..29b8fd07 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs @@ -0,0 +1,67 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Globalization; +using System.Reflection; + +namespace Newtonsoft.Json.Utilities +{ + internal abstract class ReflectionDelegateFactory + { + public Func CreateGet(MemberInfo memberInfo) + { + PropertyInfo propertyInfo = memberInfo as PropertyInfo; + if (propertyInfo != null) + return CreateGet(propertyInfo); + + FieldInfo fieldInfo = memberInfo as FieldInfo; + if (fieldInfo != null) + return CreateGet(fieldInfo); + + throw new Exception("Could not create getter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); + } + + public Action CreateSet(MemberInfo memberInfo) + { + PropertyInfo propertyInfo = memberInfo as PropertyInfo; + if (propertyInfo != null) + return CreateSet(propertyInfo); + + FieldInfo fieldInfo = memberInfo as FieldInfo; + if (fieldInfo != null) + return CreateSet(fieldInfo); + + throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); + } + + public abstract MethodCall CreateMethodCall(MethodBase method); + public abstract Func CreateDefaultConstructor(Type type); + public abstract Func CreateGet(PropertyInfo propertyInfo); + public abstract Func CreateGet(FieldInfo fieldInfo); + public abstract Action CreateSet(FieldInfo fieldInfo); + public abstract Action CreateSet(PropertyInfo propertyInfo); + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index d22752bc..5f33fa28 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -687,7 +687,7 @@ namespace Newtonsoft.Json.Utilities // CF doesn't have a Activator.CreateInstance overload that takes args // lame - if (type.IsValueType) + if (type.IsValueType && CollectionUtils.IsNullOrEmpty(args)) return Activator.CreateInstance(type); ConstructorInfo[] constructors = type.GetConstructors();