diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 821e3350..83b6e44e 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -4441,5 +4441,75 @@ keyword such as type of business."" ""newMemberWithProperty"": null }", result); } + + public class NonDefaultConstructorWithReadOnlyCollectionProperty + { + public string Title { get; set; } + public IList Categories { get; private set; } + + public NonDefaultConstructorWithReadOnlyCollectionProperty(string title) + { + Title = title; + Categories = new List(); + } + } + + [Test] + public void NonDefaultConstructorWithReadOnlyCollectionPropertyTest() + { + NonDefaultConstructorWithReadOnlyCollectionProperty c1 = new NonDefaultConstructorWithReadOnlyCollectionProperty("blah"); + c1.Categories.Add("one"); + c1.Categories.Add("two"); + + string json = JsonConvert.SerializeObject(c1, Formatting.Indented); + Assert.AreEqual(@"{ + ""Title"": ""blah"", + ""Categories"": [ + ""one"", + ""two"" + ] +}", json); + + NonDefaultConstructorWithReadOnlyCollectionProperty c2 = JsonConvert.DeserializeObject(json); + Assert.AreEqual(c1.Title, c2.Title); + Assert.AreEqual(c1.Categories.Count, c2.Categories.Count); + Assert.AreEqual("one", c2.Categories[0]); + Assert.AreEqual("two", c2.Categories[1]); + } + + public class NonDefaultConstructorWithReadOnlyDictionaryProperty + { + public string Title { get; set; } + public IDictionary Categories { get; private set; } + + public NonDefaultConstructorWithReadOnlyDictionaryProperty(string title) + { + Title = title; + Categories = new Dictionary(); + } + } + + [Test] + public void NonDefaultConstructorWithReadOnlyDictionaryPropertyTest() + { + NonDefaultConstructorWithReadOnlyDictionaryProperty c1 = new NonDefaultConstructorWithReadOnlyDictionaryProperty("blah"); + c1.Categories.Add("one", 1); + c1.Categories.Add("two", 2); + + string json = JsonConvert.SerializeObject(c1, Formatting.Indented); + Assert.AreEqual(@"{ + ""Title"": ""blah"", + ""Categories"": { + ""one"": 1, + ""two"": 2 + } +}", json); + + NonDefaultConstructorWithReadOnlyDictionaryProperty c2 = JsonConvert.DeserializeObject(json); + Assert.AreEqual(c1.Title, c2.Title); + Assert.AreEqual(c1.Categories.Count, c2.Categories.Count); + Assert.AreEqual(1, c2.Categories["one"]); + Assert.AreEqual(2, c2.Categories["two"]); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index dc3cc501..c824ed33 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -915,7 +915,47 @@ namespace Newtonsoft.Json.Serialization object value = remainingPropertyValue.Value; if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value)) + { property.ValueProvider.SetValue(createdObject, value); + } + else if (!property.Writable && value != null) + { + // handle readonly collection/dictionary properties + JsonContract propertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType); + + if (propertyContract is JsonArrayContract) + { + JsonArrayContract propertyArrayContract = propertyContract as JsonArrayContract; + + object createdObjectCollection = property.ValueProvider.GetValue(createdObject); + if (createdObjectCollection != null) + { + IWrappedCollection createdObjectCollectionWrapper = propertyArrayContract.CreateWrapper(createdObjectCollection); + IWrappedCollection newValues = propertyArrayContract.CreateWrapper(value); + + foreach (object newValue in newValues) + { + createdObjectCollectionWrapper.Add(newValue); + } + } + } + else if (propertyContract is JsonDictionaryContract) + { + JsonDictionaryContract jsonDictionaryContract = propertyContract as JsonDictionaryContract; + + object createdObjectDictionary = property.ValueProvider.GetValue(createdObject); + if (createdObjectDictionary != null) + { + IWrappedDictionary createdObjectDictionaryWrapper = jsonDictionaryContract.CreateWrapper(createdObjectDictionary); + IWrappedDictionary newValues = jsonDictionaryContract.CreateWrapper(value); + + foreach (DictionaryEntry newValue in newValues) + { + createdObjectDictionaryWrapper.Add(newValue.Key, newValue.Value); + } + } + } + } } contract.InvokeOnDeserialized(createdObject, Serializer.Context);