-Fixed using MetadataTypeAttribute with proxies

-Fixed error when deserializing undeserializable collections
This commit is contained in:
James Newton-King
2015-01-11 14:32:52 +13:00
parent a2e15adf80
commit 9a4f96aa8f
4 changed files with 262 additions and 9 deletions
@@ -173,6 +173,106 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(Guid.Empty, c2.UpdatedBy_Id);
}
[Serializable]
public partial class FaqItem
{
public FaqItem()
{
this.Sections = new HashSet<FaqSection>();
}
public int FaqId { get; set; }
public string Name { get; set; }
public bool IsDeleted { get; set; }
public virtual ICollection<FaqSection> Sections { get; set; }
}
[MetadataType(typeof(FaqItemMetadata))]
partial class FaqItem
{
[JsonProperty("FullSectionsProp")]
public ICollection<FaqSection> FullSections
{
get { return Sections; }
}
}
public class FaqItemMetadata
{
[JsonIgnore]
public virtual ICollection<FaqSection> Sections { get; set; }
}
public class FaqSection
{
}
public class FaqItemProxy : FaqItem
{
public bool IsProxy { get; set; }
public override ICollection<FaqSection> Sections
{
get { return base.Sections; }
set { base.Sections = value; }
}
}
[Test]
public void SerializeMetadataType2()
{
FaqItem c = new FaqItem();
c.FaqId = 1;
c.Sections.Add(new FaqSection());
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
Console.WriteLine(json);
StringAssert.AreEqual(@"{
""FaqId"": 1,
""Name"": null,
""IsDeleted"": false,
""FullSectionsProp"": [
{}
]
}", json);
FaqItem c2 = JsonConvert.DeserializeObject<FaqItem>(json);
Assert.AreEqual(1, c2.FaqId);
Assert.AreEqual(1, c2.Sections.Count);
}
[Test]
public void SerializeMetadataTypeInheritance()
{
FaqItemProxy c = new FaqItemProxy();
c.FaqId = 1;
c.Sections.Add(new FaqSection());
c.IsProxy = true;
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
Console.WriteLine(json);
StringAssert.AreEqual(@"{
""IsProxy"": true,
""FaqId"": 1,
""Name"": null,
""IsDeleted"": false,
""FullSectionsProp"": [
{}
]
}", json);
FaqItemProxy c2 = JsonConvert.DeserializeObject<FaqItemProxy>(json);
Assert.AreEqual(1, c2.FaqId);
Assert.AreEqual(1, c2.Sections.Count);
}
#endif
public class NullTestClass
@@ -8466,6 +8566,151 @@ Path '', line 1, position 1.");
Assert.AreEqual("base", d.BaseProperty);
Assert.AreEqual("derived", d.DerivedProperty);
}
[Test]
public void MailMessageConverterTest()
{
const string JsonMessage = @"{
""From"": {
""Address"": ""askywalker@theEmpire.gov"",
""DisplayName"": ""Darth Vader""
},
""Sender"": null,
""ReplyTo"": null,
""ReplyToList"": [],
""To"": [
{
""Address"": ""lskywalker@theRebellion.org"",
""DisplayName"": ""Luke Skywalker""
}
],
""Bcc"": [],
""CC"": [
{
""Address"": ""lorgana@alderaan.gov"",
""DisplayName"": ""Princess Leia""
}
],
""Priority"": 0,
""DeliveryNotificationOptions"": 0,
""Subject"": ""Family tree"",
""SubjectEncoding"": null,
""Headers"": [],
""HeadersEncoding"": null,
""Body"": ""<strong>I am your father!</strong>"",
""BodyEncoding"": ""US-ASCII"",
""BodyTransferEncoding"": -1,
""IsBodyHtml"": true,
""Attachments"": [
{
""FileName"": ""skywalker family tree.jpg"",
""ContentBase64"": ""AQIDBAU=""
}
],
""AlternateViews"": []
}";
System.Net.Mail.MailMessage mailMessage = JsonConvert.DeserializeObject<System.Net.Mail.MailMessage>(
JsonMessage,
new MailAddressReadConverter(),
new AttachmentReadConverter(),
new EncodingReadConverter());
Assert.AreEqual("Family tree", mailMessage.Subject);
Assert.AreEqual("Luke Skywalker", mailMessage.To[0].DisplayName);
Assert.AreEqual("skywalker family tree.jpg", mailMessage.Attachments[0].ContentDisposition.FileName);
}
public class MailAddressReadConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(System.Net.Mail.MailAddress);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var messageJObject = serializer.Deserialize<JObject>(reader);
if (messageJObject == null)
{
return null;
}
var address = messageJObject.GetValue("Address", StringComparison.OrdinalIgnoreCase).ToObject<string>();
JToken displayNameToken;
string displayName;
if (messageJObject.TryGetValue("DisplayName", StringComparison.OrdinalIgnoreCase, out displayNameToken)
&& !string.IsNullOrEmpty(displayName = displayNameToken.ToObject<string>()))
{
return new System.Net.Mail.MailAddress(address, displayName);
}
return new System.Net.Mail.MailAddress(address);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public class AttachmentReadConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(System.Net.Mail.Attachment);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var info = serializer.Deserialize<AttachmentInfo>(reader);
var attachment = info != null
? new System.Net.Mail.Attachment(new MemoryStream(Convert.FromBase64String(info.ContentBase64)), "application/octet-stream")
{
ContentDisposition = { FileName = info.FileName }
}
: null;
return attachment;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
private class AttachmentInfo
{
[JsonProperty(Required = Required.Always)]
public string FileName { get; set; }
[JsonProperty(Required = Required.Always)]
public string ContentBase64 { get; set; }
}
}
public class EncodingReadConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Encoding).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var encodingName = serializer.Deserialize<string>(reader);
if (encodingName == null)
return null;
return Encoding.GetEncoding(encodingName);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
}
public class DerivedWithPrivate : BaseWithPrivate
@@ -814,6 +814,13 @@ namespace Newtonsoft.Json.Serialization
}
else
{
// can't populate something like an IEnumerable
if (!arrayContract.CanDeserialize)
{
reader.Skip();
return existingValue;
}
value = PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(existingValue) : (IList)existingValue, reader, arrayContract, member, id);
}
@@ -229,14 +229,9 @@ namespace Newtonsoft.Json.Serialization
private static Type GetAssociateMetadataTypeFromAttribute(Type type)
{
object[] customAttributes;
#if !PORTABLE
customAttributes = type.GetCustomAttributes(false);
#else
customAttributes = type.GetTypeInfo().GetCustomAttributes(false).Cast<object>().ToArray();
#endif
Attribute[] customAttributes = ReflectionUtils.GetAttributes(type, null, true);
foreach (var attribute in customAttributes)
foreach (Attribute attribute in customAttributes)
{
Type attributeType = attribute.GetType();
@@ -670,7 +670,13 @@ namespace Newtonsoft.Json.Utilities
#if !(NETFX_CORE || PORTABLE)
public static T[] GetAttributes<T>(object attributeProvider, bool inherit) where T : Attribute
{
return (T[])GetAttributes(attributeProvider, typeof(T), inherit);
Attribute[] a = GetAttributes(attributeProvider, typeof(T), inherit);
T[] attributes = a as T[];
if (attributes != null)
return attributes;
return a.Cast<T>().ToArray();
}
public static Attribute[] GetAttributes(object attributeProvider, Type attributeType, bool inherit)
@@ -686,7 +692,7 @@ namespace Newtonsoft.Json.Utilities
{
Type t = (Type)provider;
object[] attributes = (attributeType != null) ? t.GetCustomAttributes(attributeType, inherit) : t.GetCustomAttributes(inherit);
return (Attribute[])attributes;
return attributes.Cast<Attribute>().ToArray();
}
if (provider is Assembly)