diff --git a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs index bc6e4edb..993b7546 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs @@ -25,6 +25,7 @@ using System; #if !NETFX_CORE +using System.Collections.Generic; using NUnit.Framework; #else using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -32,6 +33,7 @@ using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttrib using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute; #endif using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Tests.Serialization; using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Converters @@ -129,5 +131,118 @@ namespace Newtonsoft.Json.Tests.Converters DateTime result = JsonConvert.DeserializeObject("new Date(976918263055)", converter); Assert.AreEqual(new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc), result); } + + [Test] + public void ConverterList() + { + ConverterList l1 = new ConverterList(); + l1.Add(new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc)); + l1.Add(new DateTime(1983, 10, 9, 23, 10, 0, DateTimeKind.Utc)); + + string json = JsonConvert.SerializeObject(l1, Formatting.Indented); + Assert.AreEqual(@"[ + new Date( + 976651800000 + ), + new Date( + 434589000000 + ) +]", json); + + ConverterList l2 = JsonConvert.DeserializeObject>(json); + Assert.IsNotNull(l2); + + Assert.AreEqual(new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc), l2[0]); + Assert.AreEqual(new DateTime(1983, 10, 9, 23, 10, 0, DateTimeKind.Utc), l2[1]); + } + + [Test] + public void ConverterDictionary() + { + ConverterDictionary l1 = new ConverterDictionary(); + l1.Add("First", new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc)); + l1.Add("Second", new DateTime(1983, 10, 9, 23, 10, 0, DateTimeKind.Utc)); + + string json = JsonConvert.SerializeObject(l1, Formatting.Indented); + Assert.AreEqual(@"{ + ""First"": new Date( + 976651800000 + ), + ""Second"": new Date( + 434589000000 + ) +}", json); + + ConverterDictionary l2 = JsonConvert.DeserializeObject>(json); + Assert.IsNotNull(l2); + + Assert.AreEqual(new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc), l2["First"]); + Assert.AreEqual(new DateTime(1983, 10, 9, 23, 10, 0, DateTimeKind.Utc), l2["Second"]); + } + + [Test] + public void ConverterObject() + { + ConverterObject l1 = new ConverterObject(); + l1.Object1 = new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc); + l1.Object2 = null; + l1.ObjectNotHandled = new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc); + + string json = JsonConvert.SerializeObject(l1, Formatting.Indented); + Assert.AreEqual(@"{ + ""Object1"": new Date( + 976651800000 + ), + ""Object2"": null, + ""ObjectNotHandled"": 631122486000000000 +}", json); + + ConverterObject l2 = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(l2); + + //Assert.AreEqual(new DateTime(2000, 12, 12, 20, 10, 0, DateTimeKind.Utc), l2["First"]); + //Assert.AreEqual(new DateTime(1983, 10, 9, 23, 10, 0, DateTimeKind.Utc), l2["Second"]); + } + } + + [JsonArray(ItemConverterType = typeof(JavaScriptDateTimeConverter))] + public class ConverterList : List + { + } + + [JsonDictionary(ItemConverterType = typeof(JavaScriptDateTimeConverter))] + public class ConverterDictionary : Dictionary + { + } + + [JsonObject(ItemConverterType = typeof(JavaScriptDateTimeConverter))] + public class ConverterObject + { + public object Object1 { get; set; } + public object Object2 { get; set; } + [JsonConverter(typeof(DateIntConverter))] + public object ObjectNotHandled { get; set; } + } + + public class DateIntConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + DateTime? d = (DateTime?) value; + if (d == null) + writer.WriteNull(); + else + writer.WriteValue(d.Value.Ticks); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return new DateTime(Convert.ToInt64(reader.Value), DateTimeKind.Utc); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof (DateTime) || objectType == typeof (DateTime?); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonArrayAttributeTests.cs b/Src/Newtonsoft.Json.Tests/JsonArrayAttributeTests.cs index dbcf6db0..34314539 100644 --- a/Src/Newtonsoft.Json.Tests/JsonArrayAttributeTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonArrayAttributeTests.cs @@ -75,17 +75,5 @@ namespace Newtonsoft.Json.Tests Assert.AreEqual(DefaultValueHandling.Ignore, attribute._defaultValueHandling); Assert.AreEqual(DefaultValueHandling.Ignore, attribute.DefaultValueHandling); } - - [Test] - public void ReferenceLoopHandlingTest() - { - JsonPropertyAttribute attribute = new JsonPropertyAttribute(); - Assert.AreEqual(null, attribute._defaultValueHandling); - Assert.AreEqual(ReferenceLoopHandling.Error, attribute.ReferenceLoopHandling); - - attribute.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - Assert.AreEqual(ReferenceLoopHandling.Ignore, attribute._referenceLoopHandling); - Assert.AreEqual(ReferenceLoopHandling.Ignore, attribute.ReferenceLoopHandling); - } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs index db6b00e5..ab1882f2 100644 --- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs @@ -50,70 +50,6 @@ namespace Newtonsoft.Json.Tests [TestFixture] public class JsonConvertTest : TestFixtureBase { -#if Entities - [Test] - public void EntitiesTest() - { - Purchase purchase = new Purchase() { Id = 1 }; - purchase.PurchaseLine.Add(new PurchaseLine() { Id = 1, Purchase = purchase }); - purchase.PurchaseLine.Add(new PurchaseLine() { Id = 2, Purchase = purchase }); - - StringWriter sw = new StringWriter(); - JsonSerializer serializer = new JsonSerializer(); - serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - - using (JsonWriter jw = new JsonTextWriter(sw)) - { - jw.Formatting = Formatting.Indented; - - serializer.Serialize(jw, purchase); - } - - string json = sw.ToString(); - - Assert.AreEqual(@"{ - ""Id"": 1, - ""PurchaseLine"": [ - { - ""Id"": 1, - ""PurchaseReference"": { - ""EntityKey"": null, - ""RelationshipName"": ""EntityDataModel.PurchasePurchaseLine"", - ""SourceRoleName"": ""PurchaseLine"", - ""TargetRoleName"": ""Purchase"", - ""RelationshipSet"": null, - ""IsLoaded"": false - }, - ""EntityState"": 1, - ""EntityKey"": null - }, - { - ""Id"": 2, - ""PurchaseReference"": { - ""EntityKey"": null, - ""RelationshipName"": ""EntityDataModel.PurchasePurchaseLine"", - ""SourceRoleName"": ""PurchaseLine"", - ""TargetRoleName"": ""Purchase"", - ""RelationshipSet"": null, - ""IsLoaded"": false - }, - ""EntityState"": 1, - ""EntityKey"": null - } - ], - ""EntityState"": 1, - ""EntityKey"": null -}", json); - - Purchase newPurchase = JsonConvert.DeserializeObject(json); - Assert.AreEqual(1, newPurchase.Id); - - Assert.AreEqual(2, newPurchase.PurchaseLine.Count); - Assert.AreEqual(1, newPurchase.PurchaseLine.ElementAt(0).Id); - Assert.AreEqual(2, newPurchase.PurchaseLine.ElementAt(1).Id); - } -#endif - [Test] public void DeserializeObject_EmptyString() { diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj index e624f1d4..1e1aeb83 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj @@ -93,7 +93,12 @@ + + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj index 90b6c872..7135f3fe 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj @@ -138,7 +138,9 @@ + + @@ -149,8 +151,13 @@ + + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index aa1f60a6..f3c761dd 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -136,6 +136,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.WindowsPhone.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.WindowsPhone.csproj index 8e4aea26..f81a8c6f 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.WindowsPhone.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.WindowsPhone.csproj @@ -99,6 +99,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index c5decf04..6a3397e9 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -144,6 +144,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index fcea2c49..5c499942 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -72,5 +72,5 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.5.3.14821")] +[assembly: AssemblyFileVersion("4.5.3.14822")] #endif diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs index f8457839..70c580ee 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs @@ -1,15 +1,18 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; #if !NETFX_CORE +using System.Runtime.Serialization; using NUnit.Framework; #else using Microsoft.VisualStudio.TestTools.UnitTesting; using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute; using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute; #endif +#if NET20 +using Newtonsoft.Json.Utilities.LinqBridge; +#else +using System.Linq; +#endif using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Tests.TestObjects; using System.Reflection; @@ -59,16 +62,19 @@ namespace Newtonsoft.Json.Tests.Serialization } } +#if !NET20 public class AddressWithDataMember { [DataMember(Name = "CustomerAddress1")] public string AddressLine1 { get; set; } } +#endif [TestFixture] public class ContractResolverTests : TestFixtureBase { +#if !NET20 [Test] public void DeserializeDataMemberClassWithNoDataContract() { @@ -77,6 +83,7 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual("AddressLine1", contract.Properties[0].PropertyName); } +#endif [Test] public void ResolveProperties_IgnoreStatic() diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs index a657c114..16696ac0 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Linq; -using System.Text; using Newtonsoft.Json.Tests.TestObjects; #if !NETFX_CORE using NUnit.Framework; diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index afa4ffaf..f795d28f 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -1016,7 +1016,7 @@ keyword such as type of business."" public void IncompatibleJsonAttributeShouldThrow() { ExceptionAssert.Throws( - "JsonConverter IsoDateTimeConverter on Newtonsoft.Json.Tests.TestObjects.IncompatibleJsonAttributeClass is not compatible with member type IncompatibleJsonAttributeClass.", + "Unexpected value when converting date. Expected DateTime or DateTimeOffset, got Newtonsoft.Json.Tests.TestObjects.IncompatibleJsonAttributeClass.", () => { IncompatibleJsonAttributeClass c = new IncompatibleJsonAttributeClass(); @@ -6193,4 +6193,15 @@ Parameter name: value", } } #endif + + [JsonObject(MemberSerialization.OptIn)] + public class TestComponentSimple + { + [JsonProperty] + public int MyProperty { get; set; } + + public TestComponentSimple() + { + } + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs index 0fb4f105..d5783331 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs @@ -24,10 +24,7 @@ #endregion using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using Newtonsoft.Json.Tests.TestObjects; #if !NETFX_CORE using NUnit.Framework; @@ -42,6 +39,7 @@ namespace Newtonsoft.Json.Tests.Serialization [TestFixture] public class NullValueHandlingTests : TestFixtureBase { +#if !NET20 [Test] public void DeserializeNullIntoDateTime() { @@ -55,6 +53,7 @@ namespace Newtonsoft.Json.Tests.Serialization DateTimeTestClass c = JsonConvert.DeserializeObject(@"{DateTimeField:""""}", new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); Assert.AreEqual(c.DateTimeField, default(DateTime)); } +#endif [Test] public void NullValueHandlingSerialization() diff --git a/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs index eae64b0c..328b1ab3 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/PreserveReferencesHandlingTests.cs @@ -884,5 +884,148 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreNotEqual(myClasses1[0], myClasses2[0]); } + + [Test] + public void ReferencedIntList() + { + ReferencedList l = new ReferencedList(); + l.Add(1); + l.Add(2); + l.Add(3); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"[ + 1, + 2, + 3 +]", json); + } + + [Test] + public void ReferencedComponentList() + { + var c1 = new TestComponentSimple(); + + ReferencedList l = new ReferencedList(); + l.Add(c1); + l.Add(new TestComponentSimple()); + l.Add(c1); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"[ + { + ""$id"": ""1"", + ""MyProperty"": 0 + }, + { + ""$id"": ""2"", + ""MyProperty"": 0 + }, + { + ""$ref"": ""1"" + } +]", json); + } + + [Test] + public void ReferencedIntDictionary() + { + ReferencedDictionary l = new ReferencedDictionary(); + l.Add("First", 1); + l.Add("Second", 2); + l.Add("Third", 3); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"{ + ""First"": 1, + ""Second"": 2, + ""Third"": 3 +}", json); + } + + [Test] + public void ReferencedComponentDictionary() + { + var c1 = new TestComponentSimple(); + + ReferencedDictionary l = new ReferencedDictionary(); + l.Add("First", c1); + l.Add("Second", new TestComponentSimple()); + l.Add("Third", c1); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"{ + ""First"": { + ""$id"": ""1"", + ""MyProperty"": 0 + }, + ""Second"": { + ""$id"": ""2"", + ""MyProperty"": 0 + }, + ""Third"": { + ""$ref"": ""1"" + } +}", json); + + ReferencedDictionary d = JsonConvert.DeserializeObject>(json); + Assert.AreEqual(3, d.Count); + Assert.IsTrue(ReferenceEquals(d["First"], d["Third"])); + } + + [Test] + public void ReferencedObjectItems() + { + ReferenceObject o1 = new ReferenceObject(); + + o1.Component1 = new TestComponentSimple { MyProperty = 1 }; + o1.Component2 = o1.Component1; + o1.ComponentNotReference = new TestComponentSimple(); + o1.String = "String!"; + o1.Integer = int.MaxValue; + + string json = JsonConvert.SerializeObject(o1, Formatting.Indented); + string expected = @"{ + ""Component1"": { + ""$id"": ""1"", + ""MyProperty"": 1 + }, + ""Component2"": { + ""$ref"": ""1"" + }, + ""ComponentNotReference"": { + ""MyProperty"": 0 + }, + ""String"": ""String!"", + ""Integer"": 2147483647 +}"; + Assert.AreEqual(expected, json); + + ReferenceObject referenceObject = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(referenceObject); + + Assert.IsTrue(ReferenceEquals(referenceObject.Component1, referenceObject.Component2)); + } + } + + [JsonArray(ItemIsReference = true)] + public class ReferencedList : List + { + } + + [JsonDictionary(ItemIsReference = true)] + public class ReferencedDictionary : Dictionary + { + } + + [JsonObject(ItemIsReference = true)] + public class ReferenceObject + { + public TestComponentSimple Component1 { get; set; } + public TestComponentSimple Component2 { get; set; } + [JsonProperty(IsReference = false)] + public TestComponentSimple ComponentNotReference { get; set; } + public string String { get; set; } + public int Integer { get; set; } } } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs new file mode 100644 index 00000000..1adf1cdd --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using NUnit.Framework; + +namespace Newtonsoft.Json.Tests.Serialization +{ + [TestFixture] + public class ReferenceLoopHandlingTests : TestFixtureBase + { + [Test] + public void ReferenceLoopHandlingTest() + { + JsonPropertyAttribute attribute = new JsonPropertyAttribute(); + Assert.AreEqual(null, attribute._defaultValueHandling); + Assert.AreEqual(ReferenceLoopHandling.Error, attribute.ReferenceLoopHandling); + + attribute.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + Assert.AreEqual(ReferenceLoopHandling.Ignore, attribute._referenceLoopHandling); + Assert.AreEqual(ReferenceLoopHandling.Ignore, attribute.ReferenceLoopHandling); + } + + [Test] + public void IgnoreObjectReferenceLoop() + { + ReferenceLoopHandlingObjectContainerAttribute o = new ReferenceLoopHandlingObjectContainerAttribute(); + o.Value = o; + + string json = JsonConvert.SerializeObject(o, Formatting.Indented, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Serialize + }); + Assert.AreEqual("{}", json); + } + + [Test] + public void IgnoreObjectReferenceLoopWithPropertyOverride() + { + ReferenceLoopHandlingObjectContainerAttributeWithPropertyOverride o = new ReferenceLoopHandlingObjectContainerAttributeWithPropertyOverride(); + o.Value = o; + + string json = JsonConvert.SerializeObject(o, Formatting.Indented, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Serialize + }); + Assert.AreEqual(@"{ + ""Value"": { + ""Value"": { + ""Value"": { + ""Value"": { + ""Value"": { + ""Value"": null + } + } + } + } + } +}", json); + } + + [Test] + public void IgnoreArrayReferenceLoop() + { + ReferenceLoopHandlingList a = new ReferenceLoopHandlingList(); + a.Add(a); + + string json = JsonConvert.SerializeObject(a, Formatting.Indented, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Serialize + }); + Assert.AreEqual("[]", json); + } + + [Test] + public void IgnoreDictionaryReferenceLoop() + { + ReferenceLoopHandlingDictionary d = new ReferenceLoopHandlingDictionary(); + d.Add("First", d); + + string json = JsonConvert.SerializeObject(d, Formatting.Indented, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Serialize + }); + Assert.AreEqual("{}", json); + } + } + + [JsonArray(ItemReferenceLoopHandling = ReferenceLoopHandling.Ignore)] + public class ReferenceLoopHandlingList : List + { + } + + [JsonDictionary(ItemReferenceLoopHandling = ReferenceLoopHandling.Ignore)] + public class ReferenceLoopHandlingDictionary : Dictionary + { + } + + [JsonObject(ItemReferenceLoopHandling = ReferenceLoopHandling.Ignore)] + public class ReferenceLoopHandlingObjectContainerAttribute + { + public ReferenceLoopHandlingObjectContainerAttribute Value { get; set; } + } + + [JsonObject(ItemReferenceLoopHandling = ReferenceLoopHandling.Ignore)] + public class ReferenceLoopHandlingObjectContainerAttributeWithPropertyOverride + { + private ReferenceLoopHandlingObjectContainerAttributeWithPropertyOverride _value; + private int _getCount; + + [JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Serialize)] + public ReferenceLoopHandlingObjectContainerAttributeWithPropertyOverride Value + { + get + { + if (_getCount < 5) + { + _getCount++; + return _value; + } + return null; + } + set { _value = value; } + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs index 16dd2745..3aa96adf 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs @@ -628,7 +628,6 @@ namespace Newtonsoft.Json.Tests.Serialization testObject.AnotherTestMember[1].Add(new ContentSubClass("Second One")); testObject.AThirdTestMember = new ContentSubClass("Third One"); - JsonSerializer serializingTester = new JsonSerializer(); serializingTester.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; @@ -646,29 +645,27 @@ namespace Newtonsoft.Json.Tests.Serialization string dictionaryRef = ReflectionUtils.GetTypeName(typeof(Dictionary>), FormatterAssemblyStyle.Simple); string listRef = ReflectionUtils.GetTypeName(typeof(List), FormatterAssemblyStyle.Simple); - - Assert.AreEqual(@"{ + string expected = @"{ ""TestMember"": { ""$type"": """ + contentSubClassRef + @""", ""SomeString"": ""First One"" }, ""AnotherTestMember"": { ""$type"": """ + dictionaryRef + @""", - ""1"": { - ""$type"": """ + listRef + @""", - ""$values"": [ - { - ""$type"": """ + contentSubClassRef + @""", - ""SomeString"": ""Second One"" - } - ] - } + ""1"": [ + { + ""$type"": """ + contentSubClassRef + @""", + ""SomeString"": ""Second One"" + } + ] }, ""AThirdTestMember"": { ""$type"": """ + contentSubClassRef + @""", ""SomeString"": ""Third One"" } -}", json); +}"; + + Assert.AreEqual(expected, json); Console.WriteLine(json); StringReader sr = new StringReader(json); @@ -1013,6 +1010,129 @@ namespace Newtonsoft.Json.Tests.Serialization } } #endif + + [Test] + public void TypeNameIntList() + { + TypeNameList l = new TypeNameList(); + l.Add(1); + l.Add(2); + l.Add(3); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"[ + 1, + 2, + 3 +]", json); + } + + [Test] + public void TypeNameComponentList() + { + var c1 = new TestComponentSimple(); + + TypeNameList l = new TypeNameList(); + l.Add(c1); + l.Add(new Employee + { + BirthDate = new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc), + Department = "Department!" + }); + l.Add("String!"); + l.Add(long.MaxValue); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"[ + { + ""$type"": ""Newtonsoft.Json.Tests.Serialization.TestComponentSimple, Newtonsoft.Json.Tests"", + ""MyProperty"": 0 + }, + { + ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Employee, Newtonsoft.Json.Tests"", + ""FirstName"": null, + ""LastName"": null, + ""BirthDate"": ""2000-12-12T12:12:12Z"", + ""Department"": ""Department!"", + ""JobTitle"": null + }, + ""String!"", + 9223372036854775807 +]", json); + + TypeNameList l2 = JsonConvert.DeserializeObject>(json); + Assert.AreEqual(4, l2.Count); + + CustomAssert.IsInstanceOfType(typeof(TestComponentSimple), l2[0]); + CustomAssert.IsInstanceOfType(typeof(Employee), l2[1]); + CustomAssert.IsInstanceOfType(typeof(string), l2[2]); + CustomAssert.IsInstanceOfType(typeof(long), l2[3]); + } + + [Test] + public void TypeNameDictionary() + { + TypeNameDictionary l = new TypeNameDictionary(); + l.Add("First", new TestComponentSimple { MyProperty = 1 }); + l.Add("Second", "String!"); + l.Add("Third", long.MaxValue); + + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + Assert.AreEqual(@"{ + ""First"": { + ""$type"": ""Newtonsoft.Json.Tests.Serialization.TestComponentSimple, Newtonsoft.Json.Tests"", + ""MyProperty"": 1 + }, + ""Second"": ""String!"", + ""Third"": 9223372036854775807 +}", json); + + TypeNameDictionary l2 = JsonConvert.DeserializeObject>(json); + Assert.AreEqual(3, l2.Count); + + CustomAssert.IsInstanceOfType(typeof(TestComponentSimple), l2["First"]); + Assert.AreEqual(1, ((TestComponentSimple)l2["First"]).MyProperty); + CustomAssert.IsInstanceOfType(typeof(string), l2["Second"]); + CustomAssert.IsInstanceOfType(typeof(long), l2["Third"]); + } + + [Test] + public void TypeNameObjectItems() + { + TypeNameObject o1 = new TypeNameObject(); + + o1.Object1 = new TestComponentSimple { MyProperty = 1 }; + o1.Object2 = 123; + o1.ObjectNotHandled = new TestComponentSimple { MyProperty = int.MaxValue }; + o1.String = "String!"; + o1.Integer = int.MaxValue; + + string json = JsonConvert.SerializeObject(o1, Formatting.Indented); + string expected = @"{ + ""Object1"": { + ""$type"": ""Newtonsoft.Json.Tests.Serialization.TestComponentSimple, Newtonsoft.Json.Tests"", + ""MyProperty"": 1 + }, + ""Object2"": 123, + ""ObjectNotHandled"": { + ""MyProperty"": 2147483647 + }, + ""String"": ""String!"", + ""Integer"": 2147483647 +}"; + Assert.AreEqual(expected, json); + + TypeNameObject o2 = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(o2); + + CustomAssert.IsInstanceOfType(typeof(TestComponentSimple), o2.Object1); + Assert.AreEqual(1, ((TestComponentSimple)o2.Object1).MyProperty); + CustomAssert.IsInstanceOfType(typeof(long), o2.Object2); + CustomAssert.IsInstanceOfType(typeof(JObject), o2.ObjectNotHandled); + Assert.AreEqual(@"{ + ""MyProperty"": 2147483647 +}", o2.ObjectNotHandled.ToString()); + } } public class Message @@ -1102,4 +1222,25 @@ namespace Newtonsoft.Json.Tests.Serialization } } #endif + + [JsonArray(ItemTypeNameHandling = TypeNameHandling.All)] + public class TypeNameList : List + { + } + + [JsonDictionary(ItemTypeNameHandling = TypeNameHandling.All)] + public class TypeNameDictionary : Dictionary + { + } + + [JsonObject(ItemTypeNameHandling = TypeNameHandling.All)] + public class TypeNameObject + { + public object Object1 { get; set; } + public object Object2 { get; set; } + [JsonProperty(TypeNameHandling = TypeNameHandling.None)] + public object ObjectNotHandled { get; set; } + public string String { get; set; } + public int Integer { get; set; } + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index cadf27b7..45e07513 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -59,7 +59,7 @@ namespace Newtonsoft.Json.Converters if (reader.TokenType == JsonToken.Null) { - if (!ReflectionUtils.IsNullableType(objectType)) + if (!ReflectionUtils.IsNullable(objectType)) throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); return null; diff --git a/Src/Newtonsoft.Json/JsonArrayAttribute.cs b/Src/Newtonsoft.Json/JsonArrayAttribute.cs index 7b37275b..440c1a9e 100644 --- a/Src/Newtonsoft.Json/JsonArrayAttribute.cs +++ b/Src/Newtonsoft.Json/JsonArrayAttribute.cs @@ -35,14 +35,6 @@ namespace Newtonsoft.Json { private bool _allowNullItems; - // yuck. can't set nullable properties on an attribute in C# - // have to use this approach to get an unset default state - internal NullValueHandling? _itemNullValueHandling; - internal DefaultValueHandling? _itemDefaultValueHandling; - internal ReferenceLoopHandling? _itemReferenceLoopHandling; - internal ObjectCreationHandling? _itemObjectCreationHandling; - internal TypeNameHandling? _itemTypeNameHandling; - /// /// Gets or sets a value indicating whether null items are allowed in the collection. /// @@ -53,56 +45,6 @@ namespace Newtonsoft.Json set { _allowNullItems = value; } } - /// - /// Gets or sets the null value handling used when serializing the collection's items. - /// - /// The null value handling. - public NullValueHandling ItemNullValueHandling - { - get { return _itemNullValueHandling ?? default(NullValueHandling); } - set { _itemNullValueHandling = value; } - } - - /// - /// Gets or sets the default value handling used when serializing the collection's items. - /// - /// The default value handling. - public DefaultValueHandling ItemDefaultValueHandling - { - get { return _itemDefaultValueHandling ?? default(DefaultValueHandling); } - set { _itemDefaultValueHandling = value; } - } - - /// - /// Gets or sets the reference loop handling used when serializing the collection's items. - /// - /// The reference loop handling. - public ReferenceLoopHandling ItemReferenceLoopHandling - { - get { return _itemReferenceLoopHandling ?? default(ReferenceLoopHandling); } - set { _itemReferenceLoopHandling = value; } - } - - /// - /// Gets or sets the object creation handling used when deserializing the collection's items. - /// - /// The object creation handling. - public ObjectCreationHandling ItemObjectCreationHandling - { - get { return _itemObjectCreationHandling ?? default(ObjectCreationHandling); } - set { _itemObjectCreationHandling = value; } - } - - /// - /// Gets or sets the type name handling used when serializing the collection's items. - /// - /// The type name handling. - public TypeNameHandling ItemTypeNameHandling - { - get { return _itemTypeNameHandling ?? default(TypeNameHandling); } - set { _itemTypeNameHandling = value; } - } - /// /// Initializes a new instance of the class. /// diff --git a/Src/Newtonsoft.Json/JsonContainerAttribute.cs b/Src/Newtonsoft.Json/JsonContainerAttribute.cs index fc3a6830..ce2674e6 100644 --- a/Src/Newtonsoft.Json/JsonContainerAttribute.cs +++ b/Src/Newtonsoft.Json/JsonContainerAttribute.cs @@ -49,12 +49,21 @@ namespace Newtonsoft.Json /// The description. public string Description { get; set; } + /// + /// Gets the collection's items converter. + /// + /// The collection's items converter. + public Type ItemConverterType { get; set; } + // yuck. can't set nullable properties on an attribute in C# // have to use this approach to get an unset default state internal bool? _isReference; + internal bool? _itemIsReference; + internal ReferenceLoopHandling? _itemReferenceLoopHandling; + internal TypeNameHandling? _itemTypeNameHandling; /// - /// Gets or sets a value that indicates whether to preserve object reference data. + /// Gets or sets a value that indicates whether to preserve object references. /// /// /// true to keep object reference; otherwise, false. The default is false. @@ -65,6 +74,38 @@ namespace Newtonsoft.Json set { _isReference = value; } } + /// + /// Gets or sets a value that indicates whether to preserve collection's items references. + /// + /// + /// true to keep collection's items object references; otherwise, false. The default is false. + /// + public bool ItemIsReference + { + get { return _itemIsReference ?? default(bool); } + set { _itemIsReference = value; } + } + + /// + /// Gets or sets the reference loop handling used when serializing the collection's items. + /// + /// The reference loop handling. + public ReferenceLoopHandling ItemReferenceLoopHandling + { + get { return _itemReferenceLoopHandling ?? default(ReferenceLoopHandling); } + set { _itemReferenceLoopHandling = value; } + } + + /// + /// Gets or sets the type name handling used when serializing the collection's items. + /// + /// The type name handling. + public TypeNameHandling ItemTypeNameHandling + { + get { return _itemTypeNameHandling ?? default(TypeNameHandling); } + set { _itemTypeNameHandling = value; } + } + /// /// Initializes a new instance of the class. /// diff --git a/Src/Newtonsoft.Json/JsonDictionaryAttribute.cs b/Src/Newtonsoft.Json/JsonDictionaryAttribute.cs new file mode 100644 index 00000000..6ef4011e --- /dev/null +++ b/Src/Newtonsoft.Json/JsonDictionaryAttribute.cs @@ -0,0 +1,52 @@ +#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; + +namespace Newtonsoft.Json +{ + /// + /// Instructs the how to serialize the collection. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] + public sealed class JsonDictionaryAttribute : JsonContainerAttribute + { + /// + /// Initializes a new instance of the class. + /// + public JsonDictionaryAttribute() + { + } + + /// + /// Initializes a new instance of the class with the specified container Id. + /// + /// The container Id. + public JsonDictionaryAttribute(string id) + : base(id) + { + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index f08af6ca..e00b47a1 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -98,10 +98,12 @@ + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj index 79ac86f7..149bdd92 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj @@ -110,11 +110,13 @@ + + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index 884c7ac7..af030abe 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -117,6 +117,7 @@ + @@ -172,6 +173,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj index ac2890b4..5fd0d453 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj @@ -90,6 +90,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 43b7c101..2d1ee1c9 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -103,6 +103,7 @@ + @@ -111,6 +112,7 @@ + diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 3c97661d..d719d657 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -91,7 +91,7 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.5.3.14821")] +[assembly: AssemblyFileVersion("4.5.3.14822")] #endif [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 69a5eed7..8c069bc5 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -732,6 +732,9 @@ namespace Newtonsoft.Json.Serialization if (JsonTypeReflector.GetJsonArrayAttribute(t) != null) return CreateArrayContract(objectType); + if (JsonTypeReflector.GetJsonDictionaryAttribute(t) != null) + return CreateDictionaryContract(objectType); + if (t == typeof(JToken) || t.IsSubclassOf(typeof(JToken))) return CreateLinqContract(objectType); diff --git a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs index 7eb906e4..fe76cf48 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs @@ -39,7 +39,7 @@ namespace Newtonsoft.Json.Serialization /// /// Contract details for a used by the . /// - public class JsonArrayContract : JsonContract + public class JsonArrayContract : JsonContainerContract { /// /// Gets the of the collection items. diff --git a/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs new file mode 100644 index 00000000..b4308837 --- /dev/null +++ b/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs @@ -0,0 +1,88 @@ +#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.Reflection; +using Newtonsoft.Json.Utilities; +using System.Collections; +#if NET20 +using Newtonsoft.Json.Utilities.LinqBridge; +#else +using System.Linq; +#endif + +namespace Newtonsoft.Json.Serialization +{ + /// + /// Contract details for a used by the . + /// + public class JsonContainerContract : JsonContract + { + /// + /// Gets or sets the default collection items . + /// + /// The converter. + public JsonConverter ItemConverter { get; set; } + + /// + /// Gets or sets a value indicating whether the collection items preserve object references. + /// + /// true if collection items preserve object references; otherwise, false. + public bool? ItemIsReference { get; set; } + + /// + /// Gets or sets the collection item reference loop handling. + /// + /// The reference loop handling. + public ReferenceLoopHandling? ItemReferenceLoopHandling { get; set; } + + /// + /// Gets or sets the collection item type name handling. + /// + /// The type name handling. + public TypeNameHandling? ItemTypeNameHandling { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The underlying type for the contract. + internal JsonContainerContract(Type underlyingType) + : base(underlyingType) + { + JsonContainerAttribute jsonContainerAttribute = JsonTypeReflector.GetJsonContainerAttribute(underlyingType); + + if (jsonContainerAttribute != null) + { + if (jsonContainerAttribute.ItemConverterType != null) + ItemConverter = JsonConverterAttribute.CreateJsonConverterInstance(jsonContainerAttribute.ItemConverterType); + + ItemIsReference = jsonContainerAttribute._itemIsReference; + ItemReferenceLoopHandling = jsonContainerAttribute._itemReferenceLoopHandling; + ItemTypeNameHandling = jsonContainerAttribute._itemTypeNameHandling; + } + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs index 4bae99db..2a63e3e3 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs @@ -37,7 +37,7 @@ namespace Newtonsoft.Json.Serialization /// /// Contract details for a used by the . /// - public class JsonDictionaryContract : JsonContract + public class JsonDictionaryContract : JsonContainerContract { /// /// Gets or sets the property name resolver. diff --git a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs index 80656af8..47a62b5c 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs @@ -31,7 +31,7 @@ namespace Newtonsoft.Json.Serialization /// /// Contract details for a used by the . /// - public class JsonObjectContract : JsonContract + public class JsonObjectContract : JsonContainerContract { /// /// Gets or sets the object member serialization. diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 835d5681..cbd3be81 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -113,7 +113,7 @@ namespace Newtonsoft.Json.Serialization JsonContract contract = GetContractSafe(objectType); - JsonConverter converter = GetConverter(contract, null); + JsonConverter converter = GetConverter(contract, null, null); if (reader.TokenType == JsonToken.None && !ReadForType(reader, contract, converter != null, false)) { @@ -123,7 +123,7 @@ namespace Newtonsoft.Json.Serialization return null; } - return CreateValueNonProperty(reader, objectType, contract, converter); + return CreateValueNonProperty(reader, objectType, contract, converter, null); } private JsonSerializerProxy GetInternalSerializer() @@ -186,7 +186,7 @@ namespace Newtonsoft.Json.Serialization return token; } - private object CreateValueProperty(JsonReader reader, JsonProperty property, JsonConverter propertyConverter, object target, bool gottenCurrentValue, object currentValue) + private object CreateValueProperty(JsonReader reader, JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, object target, bool gottenCurrentValue, object currentValue) { JsonContract contract; JsonConverter converter; @@ -204,7 +204,7 @@ namespace Newtonsoft.Json.Serialization contract = GetContractSafe(currentValue.GetType()); if (contract != property.PropertyContract) - converter = GetConverter(contract, property.MemberConverter); + converter = GetConverter(contract, property.MemberConverter, containerContract); else converter = propertyConverter; } @@ -219,18 +219,18 @@ namespace Newtonsoft.Json.Serialization return converter.ReadJson(reader, objectType, currentValue, GetInternalSerializer()); } - return CreateValueInternal(reader, objectType, contract, property, currentValue); + return CreateValueInternal(reader, objectType, contract, property, containerContract, currentValue); } - private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract, JsonConverter converter) + private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract, JsonConverter converter, JsonContainerContract containerContract) { if (converter != null && converter.CanRead) return converter.ReadJson(reader, objectType, null, GetInternalSerializer()); - return CreateValueInternal(reader, objectType, contract, null, null); + return CreateValueInternal(reader, objectType, contract, null, containerContract, null); } - private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue) + private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, object existingValue) { if (contract != null && contract.ContractType == JsonContractType.Linq) return CreateJToken(reader, contract); @@ -242,7 +242,7 @@ namespace Newtonsoft.Json.Serialization // populate a typed object or generic dictionary/array // depending upon whether an objectType was supplied case JsonToken.StartObject: - return CreateObject(reader, objectType, contract, member, existingValue); + return CreateObject(reader, objectType, contract, member, containerContract, existingValue); case JsonToken.StartArray: return CreateList(reader, objectType, contract, member, existingValue, null); case JsonToken.Integer: @@ -262,7 +262,6 @@ namespace Newtonsoft.Json.Serialization return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.StartConstructor: - case JsonToken.EndConstructor: string constructorName = reader.Value.ToString(); return constructorName; @@ -287,7 +286,7 @@ namespace Newtonsoft.Json.Serialization throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); } - private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter) + private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract) { JsonConverter converter = null; if (memberConverter != null) @@ -295,6 +294,10 @@ namespace Newtonsoft.Json.Serialization // member attribute converter converter = memberConverter; } + else if (containerContract != null && containerContract.ItemConverter != null) + { + converter = containerContract.ItemConverter; + } else if (contract != null) { JsonConverter matchingConverter; @@ -311,7 +314,7 @@ namespace Newtonsoft.Json.Serialization return converter; } - private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue) + private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, object existingValue) { CheckedRead(reader); @@ -358,7 +361,11 @@ namespace Newtonsoft.Json.Serialization CheckedRead(reader); string qualifiedTypeName = reader.Value.ToString(); - if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) != TypeNameHandling.None) + TypeNameHandling resolvedTypeNameHandling = ((member != null) ? member.TypeNameHandling : null) + ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null) + ?? Serializer.TypeNameHandling; + + if (resolvedTypeNameHandling != TypeNameHandling.None) { string typeName; string assemblyName; @@ -433,7 +440,7 @@ namespace Newtonsoft.Json.Serialization if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) { CheckedRead(reader); - object value = CreateValueInternal(reader, objectType, primitiveContract, member, existingValue); + object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, existingValue); CheckedRead(reader); return value; @@ -561,7 +568,7 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For return value.ToString(); } - private void SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonReader reader, object target) + private void SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonReader reader, object target) { if (property.Ignored) { @@ -612,7 +619,7 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For } object existingValue = (useExistingValue) ? currentValue : null; - object value = CreateValueProperty(reader, property, propertyConverter, target, gottenCurrentValue, existingValue); + object value = CreateValueProperty(reader, property, propertyConverter, containerContract, 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 @@ -696,12 +703,12 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For if (contract.DictionaryValueContract == null) contract.DictionaryValueContract = GetContractSafe(contract.DictionaryValueType); - JsonConverter dictionaryValueConverter = GetConverter(contract.DictionaryValueContract, null); + JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.DictionaryValueContract, null, contract); if (!ReadForType(reader, contract.DictionaryValueContract, dictionaryValueConverter != null, false)) throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); - dictionary[keyValue] = CreateValueNonProperty(reader, contract.DictionaryValueType, contract.DictionaryValueContract, dictionaryValueConverter); + dictionary[keyValue] = CreateValueNonProperty(reader, contract.DictionaryValueType, contract.DictionaryValueContract, dictionaryValueConverter, contract); } catch (Exception ex) { @@ -763,7 +770,7 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For int index = 0; JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType); - JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null); + JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract); while (true) { @@ -780,7 +787,7 @@ To force JSON arrays to deserialize add the JsonArrayAttribute to the type.".For case JsonToken.Comment: break; default: - object value = CreateValueNonProperty(reader, contract.CollectionItemType, collectionItemContract, collectionItemConverter); + object value = CreateValueNonProperty(reader, contract.CollectionItemType, collectionItemContract, collectionItemConverter, contract); wrappedList.Add(value); break; @@ -900,18 +907,18 @@ To fix this error either change the environment to be fully trusted, change the if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter); + JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, null); - SetPropertyValue(property, propertyConverter, reader, newObject); + SetPropertyValue(property, propertyConverter, null, reader, newObject); } else { Type t = (JsonReader.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType : typeof (IDynamicMetaObjectProvider); JsonContract dynamicMemberContract = GetContractSafe(t); - JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null); + JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null); - object value = CreateValueNonProperty(reader, t, dynamicMemberContract, dynamicMemberConverter); + object value = CreateValueNonProperty(reader, t, dynamicMemberContract, dynamicMemberConverter, null); newObject.TrySetMember(memberName, value); } @@ -1075,13 +1082,13 @@ To fix this error either change the environment to be fully trusted, change the if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter); + JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract); if (!ReadForType(reader, property.PropertyContract, propertyConverter != null, false)) throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); if (!property.Ignored) - propertyValues[property] = CreateValueProperty(reader, property, propertyConverter, null, true, null); + propertyValues[property] = CreateValueProperty(reader, property, propertyConverter, contract, null, true, null); else reader.Skip(); } @@ -1193,14 +1200,14 @@ To fix this error either change the environment to be fully trusted, change the if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter); + JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract); if (!ReadForType(reader, property.PropertyContract, propertyConverter != null, false)) throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); SetPropertyPresence(reader, property, propertiesPresence); - SetPropertyValue(property, propertyConverter, reader, newObject); + SetPropertyValue(property, propertyConverter, contract, reader, newObject); } catch (Exception ex) { diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index e3aa535c..433a7172 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -58,7 +58,7 @@ namespace Newtonsoft.Json.Serialization if (jsonWriter == null) throw new ArgumentNullException("jsonWriter"); - SerializeValue(jsonWriter, value, GetContractSafe(value), null, null); + SerializeValue(jsonWriter, value, GetContractSafe(value), null, null, null); } private JsonSerializerProxy GetInternalSerializer() @@ -77,11 +77,11 @@ namespace Newtonsoft.Json.Serialization return Serializer.ContractResolver.ResolveContract(value.GetType()); } - private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContract collectionValueContract) + private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { if (contract.UnderlyingType == typeof (byte[])) { - bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract); + bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionContract, collectionValueContract); if (includeTypeDetails) { writer.WriteStartObject(); @@ -96,53 +96,53 @@ namespace Newtonsoft.Json.Serialization writer.WriteValue(value); } - private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContract collectionValueContract) + private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { - JsonConverter converter = (member != null) ? member.Converter : null; - if (value == null) { writer.WriteNull(); return; } - if ((converter != null + JsonConverter converter; + if ((((converter = (member != null) ? member.Converter : null) != null) + || ((converter = (collectionContract != null) ? collectionContract.ItemConverter : null) != null) || ((converter = valueContract.Converter) != null) || ((converter = Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null) || ((converter = valueContract.InternalConverter) != null)) && converter.CanWrite) { - SerializeConvertable(writer, converter, value, valueContract); + SerializeConvertable(writer, converter, value, valueContract, collectionContract, collectionValueContract); return; } switch (valueContract.ContractType) { case JsonContractType.Object: - SerializeObject(writer, value, (JsonObjectContract) valueContract, member, collectionValueContract); + SerializeObject(writer, value, (JsonObjectContract) valueContract, member, collectionContract, collectionValueContract); break; case JsonContractType.Array: JsonArrayContract arrayContract = (JsonArrayContract) valueContract; - SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, collectionValueContract); + SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, collectionContract, collectionValueContract); break; case JsonContractType.Primitive: - SerializePrimitive(writer, value, (JsonPrimitiveContract) valueContract, member, collectionValueContract); + SerializePrimitive(writer, value, (JsonPrimitiveContract)valueContract, member, collectionContract, collectionValueContract); break; case JsonContractType.String: SerializeString(writer, value, (JsonStringContract) valueContract); break; case JsonContractType.Dictionary: JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) valueContract; - SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, collectionValueContract); + SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, collectionContract, collectionValueContract); break; #if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE) case JsonContractType.Dynamic: - SerializeDynamic(writer, (IDynamicMetaObjectProvider) value, (JsonDynamicContract) valueContract, member, collectionValueContract); + SerializeDynamic(writer, (IDynamicMetaObjectProvider)value, (JsonDynamicContract)valueContract, member, collectionContract, collectionValueContract); break; #endif #if !(SILVERLIGHT || NETFX_CORE || PORTABLE) case JsonContractType.Serializable: - SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) valueContract, member, collectionValueContract); + SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract, member, collectionContract, collectionValueContract); break; #endif case JsonContractType.Linq: @@ -151,25 +151,35 @@ namespace Newtonsoft.Json.Serialization } } - private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract) + private bool? ResolveIsReference(JsonContract contract, JsonProperty property, JsonContainerContract collectionContract) { - if (value == null) - return false; - if (contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String) - return false; - bool? isReference = null; // value could be coming from a dictionary or array and not have a property if (property != null) isReference = property.IsReference; + if (isReference == null && collectionContract != null) + isReference = collectionContract.ItemIsReference; + if (isReference == null) isReference = contract.IsReference; + return isReference; + } + + private bool ShouldWriteReference(object value, JsonProperty property, JsonContract valueContract, JsonContainerContract collectionContract) + { + if (value == null) + return false; + if (valueContract.ContractType == JsonContractType.Primitive || valueContract.ContractType == JsonContractType.String) + return false; + + bool? isReference = ResolveIsReference(valueContract, property, collectionContract); + if (isReference == null) { - if (contract.ContractType == JsonContractType.Array) + if (valueContract.ContractType == JsonContractType.Array) isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays); else isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); @@ -181,25 +191,25 @@ namespace Newtonsoft.Json.Serialization return Serializer.ReferenceResolver.IsReferenced(this, value); } - private void WriteMemberInfoProperty(JsonWriter writer, object memberValue, JsonProperty property, JsonContract contract) + private void WriteMemberInfoProperty(JsonWriter writer, object memberValue, JsonProperty property, JsonContract contract, JsonContainerContract collectionContract) { string propertyName = property.PropertyName; - if (ShouldWriteReference(memberValue, property, contract)) + if (ShouldWriteReference(memberValue, property, contract, collectionContract)) { writer.WritePropertyName(propertyName); WriteReference(writer, memberValue); return; } - if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling, contract)) + if (!CheckForCircularReference(memberValue, property, contract, collectionContract)) return; if (memberValue == null && property.Required == Required.Always) throw new JsonSerializationException("Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); writer.WritePropertyName(propertyName); - SerializeValue(writer, memberValue, contract, property, null); + SerializeValue(writer, memberValue, contract, property, collectionContract, null); } private bool ShouldWriteProperty(object memberValue, JsonProperty property) @@ -215,11 +225,19 @@ namespace Newtonsoft.Json.Serialization return true; } - private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling, JsonContract contract) + private bool CheckForCircularReference(object value, JsonProperty property, JsonContract contract, JsonContainerContract collectionContract) { if (value == null || contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String) return true; + ReferenceLoopHandling? referenceLoopHandling = null; + + if (property != null) + referenceLoopHandling = property.ReferenceLoopHandling; + + if (referenceLoopHandling == null && collectionContract != null) + referenceLoopHandling = collectionContract.ItemReferenceLoopHandling; + if (_serializeStack.IndexOf(value) != -1) { switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling)) @@ -299,13 +317,13 @@ namespace Newtonsoft.Json.Serialization contract.InvokeOnSerialized(value, Serializer.Context); } - private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContract collectionValueContract) + private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { contract.InvokeOnSerializing(value, Serializer.Context); _serializeStack.Add(value); - WriteObjectStart(writer, value, contract, member, collectionValueContract); + WriteObjectStart(writer, value, contract, member, collectionContract, collectionValueContract); int initialDepth = writer.Top; @@ -323,7 +341,7 @@ namespace Newtonsoft.Json.Serialization if (ShouldWriteProperty(memberValue, property)) { - WriteMemberInfoProperty(writer, memberValue, property, memberContract); + WriteMemberInfoProperty(writer, memberValue, property, memberContract, contract); } } } @@ -343,17 +361,17 @@ namespace Newtonsoft.Json.Serialization contract.InvokeOnSerialized(value, Serializer.Context); } - private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContract collectionValueContract) + private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { writer.WriteStartObject(); - - bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); + + bool isReference = ResolveIsReference(contract, member, collectionContract) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); if (isReference) { writer.WritePropertyName(JsonTypeReflector.IdPropertyName); writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, value)); } - if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract)) + if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionContract, collectionValueContract)) { WriteTypeProperty(writer, contract.UnderlyingType); } @@ -380,15 +398,15 @@ namespace Newtonsoft.Json.Serialization return ((value & flag) == flag); } - private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract) + private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract collectionContract, JsonContract collectionValueContract) { - if (ShouldWriteReference(value, null, contract)) + if (ShouldWriteReference(value, null, contract, collectionContract)) { WriteReference(writer, value); } else { - if (!CheckForCircularReference(value, null, contract)) + if (!CheckForCircularReference(value, null, contract, collectionContract)) return; _serializeStack.Add(value); @@ -399,13 +417,13 @@ namespace Newtonsoft.Json.Serialization } } - private void SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContract collectionValueContract) + private void SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { contract.InvokeOnSerializing(values.UnderlyingCollection, Serializer.Context); _serializeStack.Add(values.UnderlyingCollection); - bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionValueContract); + bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionContract, collectionValueContract); writer.WriteStartArray(); @@ -421,15 +439,15 @@ namespace Newtonsoft.Json.Serialization { JsonContract valueContract = collectionItemValueContract ?? GetContractSafe(value); - if (ShouldWriteReference(value, null, valueContract)) + if (ShouldWriteReference(value, null, valueContract, contract)) { WriteReference(writer, value); } else { - if (CheckForCircularReference(value, null, contract)) + if (CheckForCircularReference(value, null, valueContract, contract)) { - SerializeValue(writer, value, valueContract, null, contract.CollectionItemContract); + SerializeValue(writer, value, valueContract, null, contract, contract.CollectionItemContract); } } } @@ -456,10 +474,10 @@ namespace Newtonsoft.Json.Serialization contract.InvokeOnSerialized(values.UnderlyingCollection, Serializer.Context); } - private bool WriteStartArray(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContract collectionValueContract) + private bool WriteStartArray(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { - bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays); - bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, collectionValueContract); + bool isReference = ResolveIsReference(contract, member, collectionContract) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays); + bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, collectionContract, collectionValueContract); bool writeMetadataObject = isReference || includeTypeDetails; if (writeMetadataObject) @@ -489,7 +507,7 @@ namespace Newtonsoft.Json.Serialization [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1903:UseOnlyApiFromTargetedFramework", MessageId = "System.Security.SecuritySafeCriticalAttribute")] [SecuritySafeCritical] #endif - private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContract collectionValueContract) + private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { if (!JsonTypeReflector.FullyTrusted) { @@ -500,7 +518,7 @@ To fix this error either change the environment to be fully trusted, change the contract.InvokeOnSerializing(value, Serializer.Context); _serializeStack.Add(value); - WriteObjectStart(writer, value, contract, member, collectionValueContract); + WriteObjectStart(writer, value, contract, member, collectionContract, collectionValueContract); SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new FormatterConverter()); value.GetObjectData(serializationInfo, Serializer.Context); @@ -508,7 +526,7 @@ To fix this error either change the environment to be fully trusted, change the foreach (SerializationEntry serializationEntry in serializationInfo) { writer.WritePropertyName(serializationEntry.Name); - SerializeValue(writer, serializationEntry.Value, GetContractSafe(serializationEntry.Value), null, null); + SerializeValue(writer, serializationEntry.Value, GetContractSafe(serializationEntry.Value), null, null, null); } writer.WriteEndObject(); @@ -519,12 +537,12 @@ To fix this error either change the environment to be fully trusted, change the #endif #if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE) - private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty member, JsonContract collectionValueContract) + private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { contract.InvokeOnSerializing(value, Serializer.Context); _serializeStack.Add(value); - WriteObjectStart(writer, value, contract, member, collectionValueContract); + WriteObjectStart(writer, value, contract, member, collectionContract, collectionValueContract); foreach (string memberName in value.GetDynamicMemberNames()) { @@ -536,7 +554,7 @@ To fix this error either change the environment to be fully trusted, change the : memberName; writer.WritePropertyName(resolvedPropertyName); - SerializeValue(writer, memberValue, GetContractSafe(memberValue), null, null); + SerializeValue(writer, memberValue, GetContractSafe(memberValue), null, null, null); } } @@ -547,9 +565,13 @@ To fix this error either change the environment to be fully trusted, change the } #endif - private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContract collectionValueContract) + private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { - if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, typeNameHandlingFlag)) + TypeNameHandling resolvedTypeNameHandling = ((member != null) ? member.TypeNameHandling : null) + ?? ((collectionContract != null) ? collectionContract.ItemTypeNameHandling : null) + ?? Serializer.TypeNameHandling; + + if (HasFlag(resolvedTypeNameHandling, typeNameHandlingFlag)) return true; if (member != null) @@ -573,13 +595,13 @@ To fix this error either change the environment to be fully trusted, change the return false; } - private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContract collectionValueContract) + private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonContract collectionValueContract) { contract.InvokeOnSerializing(values.UnderlyingDictionary, Serializer.Context); _serializeStack.Add(values.UnderlyingDictionary); - WriteObjectStart(writer, values.UnderlyingDictionary, contract, member, collectionValueContract); + WriteObjectStart(writer, values.UnderlyingDictionary, contract, member, collectionContract, collectionValueContract); if (contract.DictionaryValueContract == null) contract.DictionaryValueContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object)); @@ -604,19 +626,19 @@ To fix this error either change the environment to be fully trusted, change the object value = entry.Value; JsonContract valueContract = dictionaryValueContract ?? GetContractSafe(value); - if (ShouldWriteReference(value, null, valueContract)) + if (ShouldWriteReference(value, null, valueContract, contract)) { writer.WritePropertyName(propertyName); WriteReference(writer, value); } else { - if (!CheckForCircularReference(value, null, contract)) + if (!CheckForCircularReference(value, null, valueContract, contract)) continue; writer.WritePropertyName(propertyName); - SerializeValue(writer, value, valueContract, null, contract.DictionaryValueContract); + SerializeValue(writer, value, valueContract, null, contract, dictionaryValueContract); } } catch (Exception ex) diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs index c9861984..b53aef29 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs @@ -102,6 +102,11 @@ namespace Newtonsoft.Json.Serialization return GetJsonContainerAttribute(type) as JsonArrayAttribute; } + public static JsonDictionaryAttribute GetJsonDictionaryAttribute(Type type) + { + return GetJsonContainerAttribute(type) as JsonDictionaryAttribute; + } + #if !(SILVERLIGHT || NETFX_CORE || PORTABLE) public static SerializableAttribute GetSerializableAttribute(Type type) { @@ -212,9 +217,6 @@ namespace Newtonsoft.Json.Serialization { JsonConverter memberConverter = JsonConverterAttribute.CreateJsonConverterInstance(converterType); - if (!memberConverter.CanConvert(targetConvertedType)) - throw new JsonSerializationException("JsonConverter {0} on {1} is not compatible with member type {2}.".FormatWith(CultureInfo.InvariantCulture, memberConverter.GetType().Name, provider, targetConvertedType.Name)); - return memberConverter; }