-Fixed serializing objects with DataContract and DataMember attributes on base classes
-JsonObject and JsonProperty attributes can now be placed on an interface and used when serializing implementing objects
This commit is contained in:
@@ -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.13721")]
|
||||
[assembly: AssemblyFileVersion("4.0.2.13722")]
|
||||
#endif
|
||||
|
||||
@@ -4329,5 +4329,117 @@ keyword such as type of business.""
|
||||
string json = JsonConvert.SerializeObject(new EnumerableArrayPropertyClass());
|
||||
JsonConvert.DeserializeObject<EnumerableArrayPropertyClass>(json);
|
||||
}
|
||||
|
||||
#if !NET20
|
||||
[DataContract]
|
||||
public class BaseDataContract
|
||||
{
|
||||
[DataMember(Name = "virtualMember")]
|
||||
public virtual string VirtualMember { get; set; }
|
||||
|
||||
[DataMember(Name = "nonVirtualMember")]
|
||||
public string NonVirtualMember { get; set; }
|
||||
}
|
||||
|
||||
public class ChildDataContract : BaseDataContract
|
||||
{
|
||||
public override string VirtualMember { get; set; }
|
||||
public string NewMember { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildDataContractTest()
|
||||
{
|
||||
ChildDataContract cc = new ChildDataContract
|
||||
{
|
||||
VirtualMember = "VirtualMember!",
|
||||
NonVirtualMember = "NonVirtualMember!"
|
||||
};
|
||||
|
||||
string result = JsonConvert.SerializeObject(cc);
|
||||
Assert.AreEqual(@"{""virtualMember"":""VirtualMember!"",""nonVirtualMember"":""NonVirtualMember!""}", result);
|
||||
}
|
||||
#endif
|
||||
|
||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||
public class BaseObject
|
||||
{
|
||||
[JsonProperty(PropertyName = "virtualMember")]
|
||||
public virtual string VirtualMember { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "nonVirtualMember")]
|
||||
public string NonVirtualMember { get; set; }
|
||||
}
|
||||
|
||||
public class ChildObject : BaseObject
|
||||
{
|
||||
public override string VirtualMember { get; set; }
|
||||
public string NewMember { get; set; }
|
||||
}
|
||||
|
||||
public class ChildWithDifferentOverrideObject : BaseObject
|
||||
{
|
||||
[JsonProperty(PropertyName = "differentVirtualMember")]
|
||||
public override string VirtualMember { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildObjectTest()
|
||||
{
|
||||
ChildObject cc = new ChildObject
|
||||
{
|
||||
VirtualMember = "VirtualMember!",
|
||||
NonVirtualMember = "NonVirtualMember!"
|
||||
};
|
||||
|
||||
string result = JsonConvert.SerializeObject(cc);
|
||||
Assert.AreEqual(@"{""virtualMember"":""VirtualMember!"",""nonVirtualMember"":""NonVirtualMember!""}", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildWithDifferentOverrideObjectTest()
|
||||
{
|
||||
ChildWithDifferentOverrideObject cc = new ChildWithDifferentOverrideObject
|
||||
{
|
||||
VirtualMember = "VirtualMember!",
|
||||
NonVirtualMember = "NonVirtualMember!"
|
||||
};
|
||||
|
||||
string result = JsonConvert.SerializeObject(cc);
|
||||
Assert.AreEqual(@"{""differentVirtualMember"":""VirtualMember!"",""nonVirtualMember"":""NonVirtualMember!""}", result);
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||
public interface IInterfaceObject
|
||||
{
|
||||
[JsonProperty(PropertyName = "virtualMember")]
|
||||
[JsonConverter(typeof(IsoDateTimeConverter))]
|
||||
DateTime InterfaceMember { get; set; }
|
||||
}
|
||||
|
||||
public class ImplementInterfaceObject : IInterfaceObject
|
||||
{
|
||||
public DateTime InterfaceMember { get; set; }
|
||||
public string NewMember { get; set; }
|
||||
[JsonProperty(PropertyName = "newMemberWithProperty")]
|
||||
public string NewMemberWithProperty { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImplementInterfaceObjectTest()
|
||||
{
|
||||
ImplementInterfaceObject cc = new ImplementInterfaceObject
|
||||
{
|
||||
InterfaceMember = new DateTime(2010, 12, 31, 0, 0, 0, DateTimeKind.Utc),
|
||||
NewMember = "NewMember!"
|
||||
};
|
||||
|
||||
string result = JsonConvert.SerializeObject(cc, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""virtualMember"": ""2010-12-31T00:00:00Z"",
|
||||
""newMemberWithProperty"": null
|
||||
}", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.13721")]
|
||||
[assembly: AssemblyFileVersion("4.0.2.13722")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -766,8 +766,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType);
|
||||
|
||||
DataMemberAttribute dataMemberAttribute;
|
||||
if (dataContractAttribute != null)
|
||||
dataMemberAttribute = JsonTypeReflector.GetAttribute<DataMemberAttribute>(attributeProvider);
|
||||
if (dataContractAttribute != null && attributeProvider is MemberInfo)
|
||||
dataMemberAttribute = JsonTypeReflector.GetDataMemberAttribute((MemberInfo)attributeProvider);
|
||||
else
|
||||
dataMemberAttribute = null;
|
||||
#endif
|
||||
|
||||
@@ -96,7 +96,48 @@ namespace Newtonsoft.Json.Serialization
|
||||
#if !PocketPC && !NET20
|
||||
public static DataContractAttribute GetDataContractAttribute(Type type)
|
||||
{
|
||||
return CachedAttributeGetter<DataContractAttribute>.GetAttribute(type);
|
||||
// DataContractAttribute does not have inheritance
|
||||
DataContractAttribute result = null;
|
||||
Type currentType = type;
|
||||
while (result == null && currentType != null)
|
||||
{
|
||||
result = CachedAttributeGetter<DataContractAttribute>.GetAttribute(currentType);
|
||||
currentType = currentType.BaseType;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo)
|
||||
{
|
||||
// DataMemberAttribute does not have inheritance
|
||||
|
||||
// can't override a field
|
||||
if (memberInfo.MemberType == MemberTypes.Field)
|
||||
return CachedAttributeGetter<DataMemberAttribute>.GetAttribute(memberInfo);
|
||||
|
||||
// search property and then search base properties if nothing is returned and the property is virtual
|
||||
PropertyInfo propertyInfo = (PropertyInfo) memberInfo;
|
||||
DataMemberAttribute result = CachedAttributeGetter<DataMemberAttribute>.GetAttribute(propertyInfo);
|
||||
if (result == null)
|
||||
{
|
||||
if (propertyInfo.IsVirtual())
|
||||
{
|
||||
Type currentType = propertyInfo.DeclaringType;
|
||||
Type[] types = propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray();
|
||||
|
||||
while (result == null && currentType != null)
|
||||
{
|
||||
PropertyInfo baseProperty = (PropertyInfo)ReflectionUtils.GetMemberInfoFromType(currentType, propertyInfo);
|
||||
if (baseProperty != null && baseProperty.IsVirtual())
|
||||
result = CachedAttributeGetter<DataMemberAttribute>.GetAttribute(baseProperty);
|
||||
|
||||
currentType = currentType.BaseType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -204,38 +245,72 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
return _cachedMetadataTypeAttributeType;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static T GetAttribute<T>(Type type) where T : Attribute
|
||||
{
|
||||
T attribute;
|
||||
|
||||
#if !SILVERLIGHT && !PocketPC && !NET20
|
||||
Type metadataType = GetAssociatedMetadataType(type);
|
||||
if (metadataType != null)
|
||||
{
|
||||
T attribute = ReflectionUtils.GetAttribute<T>(metadataType, true);
|
||||
attribute = ReflectionUtils.GetAttribute<T>(metadataType, true);
|
||||
if (attribute != null)
|
||||
return attribute;
|
||||
}
|
||||
#endif
|
||||
|
||||
attribute = ReflectionUtils.GetAttribute<T>(type, true);
|
||||
if (attribute != null)
|
||||
return attribute;
|
||||
|
||||
foreach (Type typeInterface in type.GetInterfaces())
|
||||
{
|
||||
attribute = ReflectionUtils.GetAttribute<T>(typeInterface, true);
|
||||
if (attribute != null)
|
||||
return attribute;
|
||||
}
|
||||
|
||||
return ReflectionUtils.GetAttribute<T>(type, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static T GetAttribute<T>(MemberInfo memberInfo) where T : Attribute
|
||||
{
|
||||
T attribute;
|
||||
|
||||
#if !SILVERLIGHT && !PocketPC && !NET20
|
||||
Type metadataType = GetAssociatedMetadataType(memberInfo.DeclaringType);
|
||||
if (metadataType != null)
|
||||
{
|
||||
MemberInfo metadataTypeMemberInfo = metadataType.GetMember(memberInfo.Name,
|
||||
memberInfo.MemberType,
|
||||
BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).SingleOrDefault();
|
||||
MemberInfo metadataTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(metadataType, memberInfo);
|
||||
|
||||
if (metadataTypeMemberInfo != null)
|
||||
{
|
||||
T attribute = ReflectionUtils.GetAttribute<T>(metadataTypeMemberInfo, true);
|
||||
attribute = ReflectionUtils.GetAttribute<T>(metadataTypeMemberInfo, true);
|
||||
if (attribute != null)
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
attribute = ReflectionUtils.GetAttribute<T>(memberInfo, true);
|
||||
if (attribute != null)
|
||||
return attribute;
|
||||
|
||||
foreach (Type typeInterface in memberInfo.DeclaringType.GetInterfaces())
|
||||
{
|
||||
MemberInfo interfaceTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(typeInterface, memberInfo);
|
||||
|
||||
if (interfaceTypeMemberInfo != null)
|
||||
{
|
||||
attribute = ReflectionUtils.GetAttribute<T>(interfaceTypeMemberInfo, true);
|
||||
if (attribute != null)
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
|
||||
return ReflectionUtils.GetAttribute<T>(memberInfo, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static T GetAttribute<T>(ICustomAttributeProvider attributeProvider) where T : Attribute
|
||||
@@ -250,12 +325,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
return ReflectionUtils.GetAttribute<T>(attributeProvider, true);
|
||||
}
|
||||
#else
|
||||
public static T GetAttribute<T>(ICustomAttributeProvider attributeProvider) where T : Attribute
|
||||
{
|
||||
return ReflectionUtils.GetAttribute<T>(attributeProvider, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static bool? _dynamicCodeGeneration;
|
||||
|
||||
|
||||
@@ -37,6 +37,21 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal static class ReflectionUtils
|
||||
{
|
||||
public static bool IsVirtual(this PropertyInfo propertyInfo)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(propertyInfo, "propertyInfo");
|
||||
|
||||
MethodInfo m = propertyInfo.GetGetMethod();
|
||||
if (m != null && m.IsVirtual)
|
||||
return true;
|
||||
|
||||
m = propertyInfo.GetSetMethod();
|
||||
if (m != null && m.IsVirtual)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Type GetObjectType(object v)
|
||||
{
|
||||
return (v != null) ? v.GetType() : null;
|
||||
@@ -706,6 +721,9 @@ namespace Newtonsoft.Json.Utilities
|
||||
// http://hyperthink.net/blog/getcustomattributes-gotcha/
|
||||
// ICustomAttributeProvider doesn't do inheritance
|
||||
|
||||
if (attributeProvider is Type)
|
||||
return (T[])((Type)attributeProvider).GetCustomAttributes(typeof(T), inherit);
|
||||
|
||||
if (attributeProvider is Assembly)
|
||||
return (T[])Attribute.GetCustomAttributes((Assembly)attributeProvider, typeof(T), inherit);
|
||||
|
||||
@@ -851,6 +869,23 @@ namespace Newtonsoft.Json.Utilities
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemberInfo GetMemberInfoFromType(Type targetType, MemberInfo memberInfo)
|
||||
{
|
||||
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
switch (memberInfo.MemberType)
|
||||
{
|
||||
case MemberTypes.Property:
|
||||
PropertyInfo propertyInfo = (PropertyInfo) memberInfo;
|
||||
|
||||
Type[] types = propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray();
|
||||
|
||||
return targetType.GetProperty(propertyInfo.Name, bindingAttr, null, propertyInfo.PropertyType, types, null);
|
||||
default:
|
||||
return targetType.GetMember(memberInfo.Name, memberInfo.MemberType, bindingAttr).SingleOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<FieldInfo> GetFields(Type targetType, BindingFlags bindingAttr)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(targetType, "targetType");
|
||||
@@ -896,9 +931,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
PropertyInfo member = propertyInfos[i];
|
||||
if (member.DeclaringType != targetType)
|
||||
{
|
||||
Type[] types = member.GetIndexParameters().Select(p => p.ParameterType).ToArray();
|
||||
|
||||
PropertyInfo declaredMember = member.DeclaringType.GetProperty(member.Name, bindingAttr, null, member.PropertyType, types, null);
|
||||
PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType, member);
|
||||
propertyInfos[i] = declaredMember;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user