-Added support for DataContractAttribute and DataMemberAttribute to JsonSerializer
-Added support for serializing private members by marking them with JsonPropertyAttribute or DataMemberAttribute
This commit is contained in:
@@ -292,5 +292,15 @@ now brown cow?", '"', true);
|
||||
Assert.AreEqual(JsonConvert.NegativeInfinity, JsonConvert.ToString(double.NegativeInfinity));
|
||||
Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(double.NaN));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringEscaping()
|
||||
{
|
||||
string v = @"It's a good day
|
||||
""sunshine""";
|
||||
|
||||
string json = JsonConvert.ToString(v);
|
||||
Assert.AreEqual(@"""It's a good day\r\n\""sunshine\""""", json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if !SILVERLIGHT && !PocketPC
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
#endif
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Newtonsoft.Json;
|
||||
@@ -40,6 +43,7 @@ using Newtonsoft.Json.Converters;
|
||||
using System.Runtime.Serialization.Json;
|
||||
#endif
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Tests
|
||||
{
|
||||
@@ -1471,5 +1475,147 @@ keyword such as type of business.""
|
||||
|
||||
JsonConvert.SerializeObject(o, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
|
||||
}
|
||||
|
||||
public class RequestOnly
|
||||
{
|
||||
public string Request { get; set; }
|
||||
}
|
||||
|
||||
public class NonRequest
|
||||
{
|
||||
public Guid Sid { get; set; }
|
||||
public Guid Uid { get; set; }
|
||||
public IList<string> FidOrder { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PartialClassDeserialize()
|
||||
{
|
||||
string json = @"{
|
||||
""request"": ""ux.settings.update"",
|
||||
""sid"": ""14c561bd-32a8-457e-b4e5-4bba0832897f"",
|
||||
""uid"": ""30c39065-0f31-de11-9442-001e3786a8ec"",
|
||||
""fidOrder"": [
|
||||
""id"",
|
||||
""andytest_name"",
|
||||
""andytest_age"",
|
||||
""andytest_address"",
|
||||
""andytest_phone"",
|
||||
""date"",
|
||||
""title"",
|
||||
""titleId""
|
||||
],
|
||||
""entityName"": ""Andy Test"",
|
||||
""setting"": ""entity.field.order""
|
||||
}";
|
||||
|
||||
RequestOnly r = JsonConvert.DeserializeObject<RequestOnly>(json);
|
||||
Assert.AreEqual("ux.settings.update", r.Request);
|
||||
|
||||
NonRequest n = JsonConvert.DeserializeObject<NonRequest>(json);
|
||||
Assert.AreEqual(new Guid("14c561bd-32a8-457e-b4e5-4bba0832897f"), n.Sid);
|
||||
Assert.AreEqual(new Guid("30c39065-0f31-de11-9442-001e3786a8ec"), n.Uid);
|
||||
Assert.AreEqual(8, n.FidOrder.Count);
|
||||
Assert.AreEqual("id", n.FidOrder[0]);
|
||||
Assert.AreEqual("titleId", n.FidOrder[n.FidOrder.Count - 1]);
|
||||
}
|
||||
|
||||
#if !SILVERLIGHT && !PocketPC
|
||||
[MetadataType(typeof(OptInClassMetadata))]
|
||||
public class OptInClass
|
||||
{
|
||||
[DataContract]
|
||||
public class OptInClassMetadata
|
||||
{
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
[DataMember]
|
||||
public int Age { get; set; }
|
||||
public string NotIncluded { get; set; }
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public string NotIncluded { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OptInClassMetadataSerialization()
|
||||
{
|
||||
OptInClass optInClass = new OptInClass();
|
||||
optInClass.Age = 26;
|
||||
optInClass.Name = "James NK";
|
||||
optInClass.NotIncluded = "Poor me :(";
|
||||
|
||||
string json = JsonConvert.SerializeObject(optInClass, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""Name"": ""James NK"",
|
||||
""Age"": 26
|
||||
}", json);
|
||||
|
||||
OptInClass newOptInClass = JsonConvert.DeserializeObject<OptInClass>(@"{
|
||||
""Name"": ""James NK"",
|
||||
""NotIncluded"": ""Ignore me!"",
|
||||
""Age"": 26
|
||||
}");
|
||||
Assert.AreEqual(26, newOptInClass.Age);
|
||||
Assert.AreEqual("James NK", newOptInClass.Name);
|
||||
Assert.AreEqual(null, newOptInClass.NotIncluded);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PocketPC
|
||||
[DataContract]
|
||||
public class DataContractPrivateMembers
|
||||
{
|
||||
public DataContractPrivateMembers()
|
||||
{
|
||||
}
|
||||
|
||||
public DataContractPrivateMembers(string name, int age, int rank, string title)
|
||||
{
|
||||
_name = name;
|
||||
Age = age;
|
||||
Rank = rank;
|
||||
Title = title;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
private string _name;
|
||||
[DataMember(Name = "_age")]
|
||||
private int Age { get; set; }
|
||||
[JsonProperty]
|
||||
private int Rank { get; set; }
|
||||
[JsonProperty(PropertyName = "JsonTitle")]
|
||||
[DataMember(Name = "DataTitle")]
|
||||
private string Title { get; set; }
|
||||
|
||||
public string NotIncluded { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "_name: " + _name + ", _age: " + Age + ", Rank: " + Rank + ", JsonTitle: " + Title;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeDataContractPrivateMembers()
|
||||
{
|
||||
DataContractPrivateMembers c = new DataContractPrivateMembers("Jeff", 26, 10, "Dr");
|
||||
c.NotIncluded = "Hi";
|
||||
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""_name"": ""Jeff"",
|
||||
""_age"": 26,
|
||||
""Rank"": 10,
|
||||
""JsonTitle"": ""Dr""
|
||||
}", json);
|
||||
|
||||
DataContractPrivateMembers cc = JsonConvert.DeserializeObject<DataContractPrivateMembers>(json);
|
||||
Assert.AreEqual("_name: Jeff, _age: 26, Rank: 10, JsonTitle: Dr", cc.ToString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
|
||||
string json = JsonConvert.SerializeObject(privateMembersClass, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
MappingResolver = new CamelCaseMappingResolver { MemberSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
|
||||
MappingResolver = new CamelCaseMappingResolver { DefaultMembersSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
@@ -111,7 +111,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
""_internalString"": ""Internal!""
|
||||
}", new JsonSerializerSettings
|
||||
{
|
||||
MappingResolver = new CamelCaseMappingResolver { MemberSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
|
||||
MappingResolver = new CamelCaseMappingResolver { DefaultMembersSearchFlags = BindingFlags.NonPublic | BindingFlags.Instance }
|
||||
});
|
||||
|
||||
Assert.AreEqual("Private!", ReflectionUtils.GetMemberValue(typeof(PrivateMembersClass).GetField("_privateString", BindingFlags.Instance | BindingFlags.NonPublic), deserializedPrivateMembersClass));
|
||||
|
||||
@@ -40,5 +40,10 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
// return utcOffset.Hours.ToString("+00;-00") + utcOffset.Minutes.ToString("00;00");
|
||||
//}
|
||||
|
||||
protected string EscapedJson(string json)
|
||||
{
|
||||
return @"@""" + json.Replace(@"""", @"""""") + @"""";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ namespace Newtonsoft.Json
|
||||
private ObjectCreationHandling _objectCreationHandling;
|
||||
private NullValueHandling _nullValueHandling;
|
||||
private DefaultValueHandling _defaultValueHandling;
|
||||
private int _level;
|
||||
private JsonConverterCollection _converters;
|
||||
private IMappingResolver _mappingResolver;
|
||||
|
||||
@@ -258,8 +257,6 @@ namespace Newtonsoft.Json
|
||||
|
||||
private object CreateObject(JsonReader reader, Type objectType, object existingValue, JsonConverter memberConverter)
|
||||
{
|
||||
_level++;
|
||||
|
||||
object value;
|
||||
JsonConverter converter;
|
||||
|
||||
@@ -343,8 +340,6 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
_level--;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<Compile Include="Schema\UndefinedSchemaIdHandling.cs" />
|
||||
<Compile Include="Schema\ValidationEventArgs.cs" />
|
||||
<Compile Include="Schema\ValidationEventHandler.cs" />
|
||||
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
||||
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
|
||||
<Compile Include="Serialization\DefaultMappingResolver.cs" />
|
||||
<Compile Include="Serialization\IMappingResolver.cs" />
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<DocumentationFile>Bin\Release\Newtonsoft.Json.Silverlight.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Windows" />
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="system" />
|
||||
@@ -99,6 +100,7 @@
|
||||
<Compile Include="ObjectCreationHandling.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReferenceLoopHandling.cs" />
|
||||
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
||||
<Compile Include="Serialization\CamelCaseMappingResolver.cs" />
|
||||
<Compile Include="Serialization\DefaultMappingResolver.cs" />
|
||||
<Compile Include="Serialization\IMappingResolver.cs" />
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Runtime.Serialization">
|
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
@@ -149,6 +152,7 @@
|
||||
<Compile Include="Schema\JsonSchemaResolver.cs" />
|
||||
<Compile Include="Schema\JsonSchemaType.cs" />
|
||||
<Compile Include="Serialization\JsonTypeReflector.cs" />
|
||||
<Compile Include="Serialization\CachedAttributeGetter.cs" />
|
||||
<Compile Include="Utilities\ConvertUtils.cs" />
|
||||
<Compile Include="Utilities\CollectionWrapper.cs" />
|
||||
<Compile Include="Utilities\DateTimeUtils.cs" />
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
internal static class CachedAttributeGetter<T> where T : Attribute
|
||||
{
|
||||
private static readonly Dictionary<ICustomAttributeProvider, T> TypeAttributeCache = new Dictionary<ICustomAttributeProvider, T>();
|
||||
|
||||
public static T GetAttribute(ICustomAttributeProvider type)
|
||||
{
|
||||
T attribute;
|
||||
|
||||
if (TypeAttributeCache.TryGetValue(type, out attribute))
|
||||
return attribute;
|
||||
|
||||
// double check locking to avoid threading issues
|
||||
lock (TypeAttributeCache)
|
||||
{
|
||||
if (TypeAttributeCache.TryGetValue(type, out attribute))
|
||||
return attribute;
|
||||
|
||||
attribute = JsonTypeReflector.GetAttribute<T>(type);
|
||||
TypeAttributeCache[type] = attribute;
|
||||
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
@@ -39,11 +40,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private readonly Dictionary<Type, JsonMemberMappingCollection> TypeMemberMappingsCache = new Dictionary<Type, JsonMemberMappingCollection>();
|
||||
|
||||
public BindingFlags MemberSearchFlags { get; set; }
|
||||
public BindingFlags DefaultMembersSearchFlags { get; set; }
|
||||
|
||||
public DefaultMappingResolver()
|
||||
{
|
||||
MemberSearchFlags = BindingFlags.Public | BindingFlags.Instance;
|
||||
DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.Instance;
|
||||
}
|
||||
|
||||
public virtual JsonMemberMappingCollection ResolveMappings(Type type)
|
||||
@@ -68,7 +69,32 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
protected virtual List<MemberInfo> GetSerializableMembers(Type objectType)
|
||||
{
|
||||
return ReflectionUtils.GetFieldsAndProperties(objectType, MemberSearchFlags);
|
||||
#if !PocketPC
|
||||
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType);
|
||||
#endif
|
||||
|
||||
List<MemberInfo> defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags);
|
||||
List<MemberInfo> allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||||
|
||||
List<MemberInfo> serializableMembers = new List<MemberInfo>();
|
||||
foreach (MemberInfo member in allMembers)
|
||||
{
|
||||
if (defaultMembers.Contains(member))
|
||||
{
|
||||
serializableMembers.Add(member);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member) != null)
|
||||
serializableMembers.Add(member);
|
||||
#if !PocketPC
|
||||
else if (dataContractAttribute != null && JsonTypeReflector.GetAttribute<DataMemberAttribute>(member) != null)
|
||||
serializableMembers.Add(member);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return serializableMembers;
|
||||
}
|
||||
|
||||
private JsonMemberMappingCollection CreateMemberMappings(Type objectType)
|
||||
@@ -85,7 +111,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
JsonMemberMapping memberMapping = CreateMemberMapping(memberSerialization, member);
|
||||
|
||||
memberMappings.AddMapping(memberMapping);
|
||||
if (memberMapping != null)
|
||||
memberMappings.AddMapping(memberMapping);
|
||||
}
|
||||
|
||||
return memberMappings;
|
||||
@@ -93,19 +120,48 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
protected virtual JsonMemberMapping CreateMemberMapping(MemberSerialization memberSerialization, MemberInfo member)
|
||||
{
|
||||
#if !PocketPC
|
||||
DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType);
|
||||
|
||||
DataMemberAttribute dataMemberAttribute;
|
||||
if (dataContractAttribute != null)
|
||||
dataMemberAttribute = JsonTypeReflector.GetAttribute<DataMemberAttribute>(member);
|
||||
else
|
||||
dataMemberAttribute = null;
|
||||
#endif
|
||||
|
||||
JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member);
|
||||
bool hasIgnoreAttribute = (JsonTypeReflector.GetAttribute<JsonIgnoreAttribute>(member) != null);
|
||||
|
||||
string mappedName = (propertyAttribute != null && propertyAttribute.PropertyName != null)
|
||||
? propertyAttribute.PropertyName
|
||||
: member.Name;
|
||||
string mappedName;
|
||||
if (propertyAttribute != null && propertyAttribute.PropertyName != null)
|
||||
mappedName = propertyAttribute.PropertyName;
|
||||
#if !PocketPC
|
||||
else if (dataMemberAttribute != null && dataMemberAttribute.Name != null)
|
||||
mappedName = dataMemberAttribute.Name;
|
||||
#endif
|
||||
else
|
||||
mappedName = member.Name;
|
||||
|
||||
string resolvedMappedName = ResolveMappingName(mappedName);
|
||||
|
||||
bool required = (propertyAttribute != null) ? propertyAttribute.IsRequired : false;
|
||||
bool required;
|
||||
if (propertyAttribute != null)
|
||||
required = propertyAttribute.IsRequired;
|
||||
#if !PocketPC
|
||||
else if (dataMemberAttribute != null)
|
||||
required = dataMemberAttribute.IsRequired;
|
||||
#endif
|
||||
else
|
||||
required = false;
|
||||
|
||||
bool ignored = (hasIgnoreAttribute
|
||||
|| (memberSerialization == MemberSerialization.OptIn && propertyAttribute == null));
|
||||
bool ignored = (hasIgnoreAttribute ||
|
||||
(memberSerialization == MemberSerialization.OptIn
|
||||
&& propertyAttribute == null
|
||||
#if !PocketPC
|
||||
&& dataMemberAttribute == null
|
||||
#endif
|
||||
));
|
||||
|
||||
bool readable = ReflectionUtils.CanReadMemberValue(member);
|
||||
bool writable = ReflectionUtils.CanSetMemberValue(member);
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
@@ -38,36 +39,36 @@ namespace Newtonsoft.Json.Serialization
|
||||
internal static class JsonTypeReflector
|
||||
{
|
||||
private static readonly Dictionary<ICustomAttributeProvider, Type> ConverterTypeCache = new Dictionary<ICustomAttributeProvider, Type>();
|
||||
private static readonly Dictionary<Type, JsonContainerAttribute> TypeContainerAttributeCache = new Dictionary<Type, JsonContainerAttribute>();
|
||||
private static readonly Dictionary<Type, Type> AssociatedMetadataTypesCache = new Dictionary<Type, Type>();
|
||||
|
||||
public static JsonContainerAttribute GetJsonContainerAttribute(Type type)
|
||||
{
|
||||
JsonContainerAttribute containerAttribute;
|
||||
|
||||
if (TypeContainerAttributeCache.TryGetValue(type, out containerAttribute))
|
||||
return containerAttribute;
|
||||
|
||||
// double check locking to avoid threading issues
|
||||
lock (TypeContainerAttributeCache)
|
||||
{
|
||||
if (TypeContainerAttributeCache.TryGetValue(type, out containerAttribute))
|
||||
return containerAttribute;
|
||||
|
||||
containerAttribute = ReflectionUtils.GetAttribute<JsonContainerAttribute>(type);
|
||||
TypeContainerAttributeCache[type] = containerAttribute;
|
||||
|
||||
return containerAttribute;
|
||||
}
|
||||
return CachedAttributeGetter<JsonContainerAttribute>.GetAttribute(type);
|
||||
}
|
||||
|
||||
#if !PocketPC
|
||||
public static DataContractAttribute GetDataContractAttribute(Type type)
|
||||
{
|
||||
return CachedAttributeGetter<DataContractAttribute>.GetAttribute(type);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static MemberSerialization GetObjectMemberSerialization(Type objectType)
|
||||
{
|
||||
JsonObjectAttribute objectAttribute = GetJsonContainerAttribute(objectType) as JsonObjectAttribute;
|
||||
|
||||
if (objectAttribute == null)
|
||||
{
|
||||
#if !PocketPC
|
||||
DataContractAttribute dataContractAttribute = GetDataContractAttribute(objectType);
|
||||
|
||||
if (dataContractAttribute != null)
|
||||
return MemberSerialization.OptIn;
|
||||
#endif
|
||||
|
||||
return MemberSerialization.OptOut;
|
||||
|
||||
}
|
||||
|
||||
return objectAttribute.MemberSerialization;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user