diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 44cd7496..cef54af8 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -41,5 +41,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: [assembly: AssemblyVersion("4.0.2.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.0.2.14001")] +[assembly: AssemblyFileVersion("4.0.2.14002")] #endif diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 3bc15e63..83ed3f26 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -4641,5 +4641,48 @@ keyword such as type of business."" ""BaseClassValue"": ""BaseClassValue!"" }", json); } + + public class PrivateMembersClassWithAttributes + { + public PrivateMembersClassWithAttributes(string privateString, string internalString, string readonlyString) + { + _privateString = privateString; + _readonlyString = readonlyString; + _internalString = internalString; + } + + public PrivateMembersClassWithAttributes() + { + _readonlyString = "default!"; + } + + [JsonProperty] + private string _privateString; + [JsonProperty] + private readonly string _readonlyString; + [JsonProperty] + internal string _internalString; + + public string UseValue() + { + return _readonlyString; + } + } + + [Test] + public void PrivateMembersClassWithAttributesTest() + { + PrivateMembersClassWithAttributes c1 = new PrivateMembersClassWithAttributes("privateString!", "internalString!", "readonlyString!"); + + string json = JsonConvert.SerializeObject(c1, Formatting.Indented); + Assert.AreEqual(@"{ + ""_privateString"": ""privateString!"", + ""_readonlyString"": ""readonlyString!"", + ""_internalString"": ""internalString!"" +}", json); + + PrivateMembersClassWithAttributes c2 = JsonConvert.DeserializeObject(json); + Assert.AreEqual("readonlyString!", c2.UseValue()); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 85d5dfa4..a1c9d631 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -110,7 +110,7 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.0.2.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.0.2.14001")] +[assembly: AssemblyFileVersion("4.0.2.14002")] #endif [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index f05edcd1..12962617 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -367,7 +367,8 @@ namespace Newtonsoft.Json.Serialization property.PropertyType = parameterInfo.ParameterType; bool allowNonPublicAccess; - SetPropertySettingsFromAttributes(property, parameterInfo, parameterInfo.Name, parameterInfo.Member.DeclaringType, MemberSerialization.OptOut, out allowNonPublicAccess); + bool hasExplicitAttribute; + SetPropertySettingsFromAttributes(property, parameterInfo, parameterInfo.Name, parameterInfo.Member.DeclaringType, MemberSerialization.OptOut, out allowNonPublicAccess, out hasExplicitAttribute); property.Readable = false; property.Writable = true; @@ -783,10 +784,11 @@ namespace Newtonsoft.Json.Serialization property.ValueProvider = CreateMemberValueProvider(member); bool allowNonPublicAccess; - SetPropertySettingsFromAttributes(property, member, member.Name, member.DeclaringType, memberSerialization, out allowNonPublicAccess); + bool hasExplicitAttribute; + SetPropertySettingsFromAttributes(property, member, member.Name, member.DeclaringType, memberSerialization, out allowNonPublicAccess, out hasExplicitAttribute); property.Readable = ReflectionUtils.CanReadMemberValue(member, allowNonPublicAccess); - property.Writable = ReflectionUtils.CanSetMemberValue(member, allowNonPublicAccess); + property.Writable = ReflectionUtils.CanSetMemberValue(member, allowNonPublicAccess, hasExplicitAttribute); property.ShouldSerialize = CreateShouldSerializeTest(member); SetIsSpecifiedActions(property, member); @@ -794,8 +796,10 @@ namespace Newtonsoft.Json.Serialization return property; } - private void SetPropertySettingsFromAttributes(JsonProperty property, ICustomAttributeProvider attributeProvider, string name, Type declaringType, MemberSerialization memberSerialization, out bool allowNonPublicAccess) + private void SetPropertySettingsFromAttributes(JsonProperty property, ICustomAttributeProvider attributeProvider, string name, Type declaringType, MemberSerialization memberSerialization, out bool allowNonPublicAccess, out bool hasExplicitAttribute) { + hasExplicitAttribute = false; + #if !PocketPC && !NET20 DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType); @@ -807,6 +811,9 @@ namespace Newtonsoft.Json.Serialization #endif JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + if (propertyAttribute != null) + hasExplicitAttribute = true; + bool hasIgnoreAttribute = (JsonTypeReflector.GetAttribute(attributeProvider) != null); string mappedName; @@ -859,9 +866,13 @@ namespace Newtonsoft.Json.Serialization allowNonPublicAccess = true; if (propertyAttribute != null) allowNonPublicAccess = true; + #if !PocketPC && !NET20 if (dataMemberAttribute != null) + { allowNonPublicAccess = true; + hasExplicitAttribute = true; + } #endif } diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index bf7a0b6a..1f4ea291 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -626,17 +626,18 @@ namespace Newtonsoft.Json.Utilities /// /// The MemberInfo to determine whether can be set. /// if set to true then allow the member to be set non-publicly. + /// if set to true then allow the member to be set if read-only. /// /// true if the specified MemberInfo can be set; otherwise, false. /// - public static bool CanSetMemberValue(MemberInfo member, bool nonPublic) + public static bool CanSetMemberValue(MemberInfo member, bool nonPublic, bool canSetReadOnly) { switch (member.MemberType) { case MemberTypes.Field: FieldInfo fieldInfo = (FieldInfo)member; - if (fieldInfo.IsInitOnly) + if (fieldInfo.IsInitOnly && !canSetReadOnly) return false; if (nonPublic) return true;