-Added support for serializing extension data
-Added support for reference loop handling and type name handling to extension data -Bug fixes
This commit is contained in:
@@ -75,4 +75,4 @@ using System.Security;
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
[assembly: AssemblyFileVersion("5.0.6.16604")]
|
||||
[assembly: AssemblyFileVersion("5.0.6.16606")]
|
||||
|
||||
@@ -534,6 +534,27 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
public IDictionary<object, object> ExtensionData;
|
||||
}
|
||||
|
||||
public class PublicNoReadExtensionDataAttributeTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
[JsonExtensionData(ReadData = false)]
|
||||
public IDictionary<object, object> ExtensionData;
|
||||
}
|
||||
|
||||
public class PublicNoWriteExtensionDataAttributeTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
[JsonExtensionData(WriteData = false)]
|
||||
public IDictionary<object, object> ExtensionData;
|
||||
}
|
||||
|
||||
public class PublicJTokenExtensionDataAttributeTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
[JsonExtensionData]
|
||||
public IDictionary<string, JToken> ExtensionData;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeDirectoryAccount()
|
||||
{
|
||||
@@ -558,9 +579,175 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
}
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{""Name"":""Name!"",""Test"":1}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializePublicExtensionDataNull()
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(new PublicExtensionDataAttributeTestClass
|
||||
{
|
||||
Name = "Name!"
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{""Name"":""Name!""}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializePublicNoWriteExtensionData()
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(new PublicNoWriteExtensionDataAttributeTestClass
|
||||
{
|
||||
Name = "Name!",
|
||||
ExtensionData = new Dictionary<object, object>
|
||||
{
|
||||
{ "Test", 1 }
|
||||
}
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{""Name"":""Name!""}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeNoReadPublicExtensionData()
|
||||
{
|
||||
PublicNoReadExtensionDataAttributeTestClass c = JsonConvert.DeserializeObject<PublicNoReadExtensionDataAttributeTestClass>(@"{""Name"":""Name!"",""Test"":1}");
|
||||
|
||||
Assert.AreEqual(null, c.ExtensionData);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializePublicExtensionDataCircularReference()
|
||||
{
|
||||
var c = new PublicExtensionDataAttributeTestClass
|
||||
{
|
||||
Name = "Name!",
|
||||
ExtensionData = new Dictionary<object, object>
|
||||
{
|
||||
{ "Test", 1 }
|
||||
}
|
||||
};
|
||||
c.ExtensionData["Self"] = c;
|
||||
|
||||
string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings
|
||||
{
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.All,
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""$id"": ""1"",
|
||||
""Name"": ""Name!"",
|
||||
""Test"": 1,
|
||||
""Self"": {
|
||||
""$ref"": ""1""
|
||||
}
|
||||
}", json);
|
||||
|
||||
var c2 = JsonConvert.DeserializeObject<PublicExtensionDataAttributeTestClass>(json, new JsonSerializerSettings
|
||||
{
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.All
|
||||
});
|
||||
|
||||
Assert.AreEqual("Name!", c2.Name);
|
||||
|
||||
PublicExtensionDataAttributeTestClass bizzaroC2 = (PublicExtensionDataAttributeTestClass)c2.ExtensionData["Self"];
|
||||
|
||||
Assert.AreEqual(c2, bizzaroC2);
|
||||
Assert.AreEqual(1, (long)bizzaroC2.ExtensionData["Test"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializePublicJTokenExtensionDataCircularReference()
|
||||
{
|
||||
string json = @"{
|
||||
""$id"": ""1"",
|
||||
""Name"": ""Name!"",
|
||||
""Test"": 1,
|
||||
""Self"": {
|
||||
""$ref"": ""1""
|
||||
}
|
||||
}";
|
||||
|
||||
var c2 = JsonConvert.DeserializeObject<PublicJTokenExtensionDataAttributeTestClass>(json, new JsonSerializerSettings
|
||||
{
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.All
|
||||
});
|
||||
|
||||
Assert.AreEqual("Name!", c2.Name);
|
||||
|
||||
JObject bizzaroC2 = (JObject)c2.ExtensionData["Self"];
|
||||
|
||||
Assert.AreEqual("Name!", (string)bizzaroC2["Name"]);
|
||||
Assert.AreEqual(1, (int)bizzaroC2["Test"]);
|
||||
|
||||
Assert.AreEqual(1, (int)c2.ExtensionData["Test"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializePublicExtensionDataTypeNamdHandling()
|
||||
{
|
||||
string json = @"{
|
||||
""$id"": ""1"",
|
||||
""Name"": ""Name!"",
|
||||
""Test"": 1,
|
||||
""Self"": {
|
||||
""$type"": ""Newtonsoft.Json.Tests.TestObjects.WagePerson, Newtonsoft.Json.Tests"",
|
||||
""HourlyWage"": 2.0,
|
||||
""Name"": null,
|
||||
""BirthDate"": ""0001-01-01T00:00:00"",
|
||||
""LastModified"": ""0001-01-01T00:00:00""
|
||||
}
|
||||
}";
|
||||
|
||||
PublicExtensionDataAttributeTestClass c2 = JsonConvert.DeserializeObject<PublicExtensionDataAttributeTestClass>(json, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.Objects
|
||||
});
|
||||
|
||||
Assert.AreEqual("Name!", c2.Name);
|
||||
|
||||
WagePerson bizzaroC2 = (WagePerson)c2.ExtensionData["Self"];
|
||||
|
||||
Assert.AreEqual(2m, bizzaroC2.HourlyWage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializePublicExtensionDataTypeNamdHandling()
|
||||
{
|
||||
PublicExtensionDataAttributeTestClass c = new PublicExtensionDataAttributeTestClass
|
||||
{
|
||||
Name = "Name!",
|
||||
ExtensionData = new Dictionary<object, object>
|
||||
{
|
||||
{
|
||||
"Test", new WagePerson
|
||||
{
|
||||
HourlyWage = 2.1m
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.Objects,
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""$type"": ""Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+PublicExtensionDataAttributeTestClass, Newtonsoft.Json.Tests"",
|
||||
""Name"": ""Name!"",
|
||||
""Test"": {
|
||||
""$type"": ""Newtonsoft.Json.Tests.TestObjects.WagePerson, Newtonsoft.Json.Tests"",
|
||||
""HourlyWage"": 2.1,
|
||||
""Name"": null,
|
||||
""BirthDate"": ""0001-01-01T00:00:00"",
|
||||
""LastModified"": ""0001-01-01T00:00:00""
|
||||
}
|
||||
}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializePublicExtensionData()
|
||||
{
|
||||
@@ -575,7 +762,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
Assert.AreEqual("Name!", c.Name);
|
||||
Assert.AreEqual(2, c.ExtensionData.Count);
|
||||
|
||||
Assert.AreEqual("NoMatch!", (string)(JValue)c.ExtensionData["NoMatch"]);
|
||||
Assert.AreEqual("NoMatch!", (string)c.ExtensionData["NoMatch"]);
|
||||
|
||||
// the ExtensionData property is put into the extension data
|
||||
// inception
|
||||
@@ -603,19 +790,19 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
var c = JsonConvert.DeserializeObject<FieldExtensionDataAttributeTestClass>("{'first':1,'second':2}");
|
||||
|
||||
Assert.AreEqual(2, c.ExtensionData.Count);
|
||||
Assert.AreEqual(1, (int)(JToken)c.ExtensionData["first"]);
|
||||
Assert.AreEqual(2, (int)(JToken)c.ExtensionData["second"]);
|
||||
Assert.AreEqual(1, (long)c.ExtensionData["first"]);
|
||||
Assert.AreEqual(2, (long)c.ExtensionData["second"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MultipleExtensionDataAttributesTest()
|
||||
{
|
||||
var c = JsonConvert.DeserializeObject<MultipleExtensionDataAttributesTestClass>("{'first':1,'second':2}");
|
||||
var c = JsonConvert.DeserializeObject<MultipleExtensionDataAttributesTestClass>("{'first':[1],'second':[2]}");
|
||||
|
||||
Assert.AreEqual(null, c.ExtensionData1);
|
||||
Assert.AreEqual(2, c.ExtensionData2.Count);
|
||||
Assert.AreEqual(1, (int)c.ExtensionData2["first"]);
|
||||
Assert.AreEqual(2, (int)c.ExtensionData2["second"]);
|
||||
Assert.AreEqual(1, (int)((JArray)c.ExtensionData2["first"])[0]);
|
||||
Assert.AreEqual(2, (int)((JArray)c.ExtensionData2["second"])[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -9166,6 +9353,45 @@ Parameter name: value",
|
||||
]", json);
|
||||
}
|
||||
|
||||
public class Foo2
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore]
|
||||
public void SerializeMultipleObjectsFromStream()
|
||||
{
|
||||
StringReader sr = new StringReader(@"{ ""name"": ""bar"" }{ ""name"": ""baz"" }");
|
||||
|
||||
var reader1 = new JsonTextReader(sr);
|
||||
var serializer1 = new JsonSerializer { };
|
||||
var foo1 = serializer1.Deserialize<Foo2>(reader1);
|
||||
Assert.AreEqual("bar", foo1.Name);
|
||||
|
||||
var reader2 = new JsonTextReader(sr);
|
||||
var serializer2 = new JsonSerializer { };
|
||||
var foo2 = serializer2.Deserialize<Foo2>(reader2);
|
||||
Assert.AreEqual("baz", foo2.Name);
|
||||
}
|
||||
|
||||
#if !(PORTABLE || PORTABLE40)
|
||||
[Test]
|
||||
public void SerializeDictionaryWithStructKey()
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(
|
||||
new Dictionary<Size, Size> { { new Size(1, 2), new Size(3, 4) } }
|
||||
);
|
||||
|
||||
Assert.AreEqual(@"{""1, 2"":""3, 4""}", json);
|
||||
|
||||
Dictionary<Size, Size> d = JsonConvert.DeserializeObject<Dictionary<Size, Size>>(json);
|
||||
|
||||
Assert.AreEqual(new Size(1, 2), d.Keys.First());
|
||||
Assert.AreEqual(new Size(3, 4), d.Values.First());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void DeserializeCustomReferenceResolver()
|
||||
{
|
||||
|
||||
@@ -8,5 +8,13 @@ namespace Newtonsoft.Json
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class JsonExtensionDataAttribute : Attribute
|
||||
{
|
||||
public bool WriteData { get; set; }
|
||||
public bool ReadData { get; set; }
|
||||
|
||||
public JsonExtensionDataAttribute()
|
||||
{
|
||||
WriteData = true;
|
||||
ReadData = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,6 @@ using System.Security;
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
[assembly: AssemblyFileVersion("5.0.6.16604")]
|
||||
[assembly: AssemblyFileVersion("5.0.6.16606")]
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -391,32 +391,35 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
contract.ExtensionDataSetter = GetExtensionDataForType(contract.NonNullableUnderlyingType);
|
||||
MemberInfo extensionDataMember = GetExtensionDataMemberForType(contract.NonNullableUnderlyingType);
|
||||
if (extensionDataMember != null)
|
||||
SetExtensionDataDelegates(contract, extensionDataMember);
|
||||
|
||||
return contract;
|
||||
}
|
||||
|
||||
private ExtensionDataSetter GetExtensionDataForType(Type type)
|
||||
private MemberInfo GetExtensionDataMemberForType(Type type)
|
||||
{
|
||||
ExtensionDataSetter extensionDataSetter = null;
|
||||
|
||||
foreach (Type baseType in GetClassHierarchyForType(type))
|
||||
{
|
||||
IList<MemberInfo> members = new List<MemberInfo>();
|
||||
members.AddRange(baseType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
members.AddRange(baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
|
||||
foreach (MemberInfo member in members)
|
||||
IEnumerable<MemberInfo> members = GetClassHierarchyForType(type).SelectMany(baseType =>
|
||||
{
|
||||
MemberTypes memberType = member.MemberType();
|
||||
IList<MemberInfo> m = new List<MemberInfo>();
|
||||
m.AddRange(baseType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
m.AddRange(baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
|
||||
return m;
|
||||
});
|
||||
|
||||
MemberInfo extensionDataMember = members.LastOrDefault(m =>
|
||||
{
|
||||
MemberTypes memberType = m.MemberType();
|
||||
if (memberType != MemberTypes.Property && memberType != MemberTypes.Field)
|
||||
continue;
|
||||
return false;
|
||||
|
||||
// last instance of attribute wins on type if there are multiple
|
||||
if (!member.IsDefined(typeof(JsonExtensionDataAttribute), false))
|
||||
continue;
|
||||
if (!m.IsDefined(typeof(JsonExtensionDataAttribute), false))
|
||||
return false;
|
||||
|
||||
Type t = ReflectionUtils.GetMemberUnderlyingType(member);
|
||||
Type t = ReflectionUtils.GetMemberUnderlyingType(m);
|
||||
|
||||
Type dictionaryType;
|
||||
if (ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out dictionaryType))
|
||||
@@ -424,39 +427,122 @@ namespace Newtonsoft.Json.Serialization
|
||||
Type keyType = dictionaryType.GetGenericArguments()[0];
|
||||
Type valueType = dictionaryType.GetGenericArguments()[1];
|
||||
|
||||
// change type to a class if it is the base interface so it can be instantiated if needed
|
||||
if (ReflectionUtils.IsGenericDefinition(t, typeof(IDictionary<,>)))
|
||||
t = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
|
||||
|
||||
if (keyType.IsAssignableFrom(typeof(string)) && valueType.IsAssignableFrom(typeof(JToken)))
|
||||
{
|
||||
MethodInfo addMethod = t.GetMethod("Add", new [] { keyType, valueType });
|
||||
Func<object, object> getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(member);
|
||||
Action<object, object> setExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(member);
|
||||
Func<object> createExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(t);
|
||||
MethodCall<object, object> setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(addMethod);
|
||||
|
||||
extensionDataSetter = (o, key, value) =>
|
||||
{
|
||||
object dictionary = getExtensionDataDictionary(o);
|
||||
if (dictionary == null)
|
||||
{
|
||||
dictionary = createExtensionDataDictionary();
|
||||
setExtensionDataDictionary(o, dictionary);
|
||||
}
|
||||
|
||||
setExtensionDataDictionaryValue(dictionary, key, value);
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary<string, JToken>.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(member.DeclaringType), member.Name));
|
||||
}
|
||||
throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary<string, JToken>.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType), m.Name));
|
||||
});
|
||||
|
||||
return extensionDataMember;
|
||||
}
|
||||
|
||||
private static void SetExtensionDataDelegates(JsonObjectContract contract, MemberInfo member)
|
||||
{
|
||||
JsonExtensionDataAttribute extensionDataAttribute = ReflectionUtils.GetAttribute<JsonExtensionDataAttribute>(member);
|
||||
if (extensionDataAttribute == null)
|
||||
return;
|
||||
|
||||
Type t = ReflectionUtils.GetMemberUnderlyingType(member);
|
||||
|
||||
Type dictionaryType;
|
||||
ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out dictionaryType);
|
||||
|
||||
Type keyType = dictionaryType.GetGenericArguments()[0];
|
||||
Type valueType = dictionaryType.GetGenericArguments()[1];
|
||||
bool isJTokenValueType = typeof(JToken).IsAssignableFrom(valueType);
|
||||
|
||||
// change type to a class if it is the base interface so it can be instantiated if needed
|
||||
if (ReflectionUtils.IsGenericDefinition(t, typeof(IDictionary<,>)))
|
||||
t = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
|
||||
|
||||
MethodInfo addMethod = t.GetMethod("Add", new[] { keyType, valueType });
|
||||
Func<object, object> getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(member);
|
||||
Action<object, object> setExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(member);
|
||||
Func<object> createExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(t);
|
||||
MethodCall<object, object> setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(addMethod);
|
||||
|
||||
ExtensionDataSetter extensionDataSetter = (o, key, value) =>
|
||||
{
|
||||
object dictionary = getExtensionDataDictionary(o);
|
||||
if (dictionary == null)
|
||||
{
|
||||
dictionary = createExtensionDataDictionary();
|
||||
setExtensionDataDictionary(o, dictionary);
|
||||
}
|
||||
|
||||
// convert object value to JToken so it is compatible with dictionary
|
||||
// could happen because of primitive types, type name handling and references
|
||||
if (isJTokenValueType && !(value is JToken))
|
||||
value = JToken.FromObject(value);
|
||||
|
||||
setExtensionDataDictionaryValue(dictionary, key, value);
|
||||
};
|
||||
|
||||
Type enumerableWrapper = typeof(DictionaryEnumerator<,>).MakeGenericType(keyType, valueType);
|
||||
ConstructorInfo constructors = enumerableWrapper.GetConstructors().First();
|
||||
MethodCall<object, object> createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(constructors);
|
||||
|
||||
ExtensionDataGetter extensionDataGetter = o =>
|
||||
{
|
||||
object dictionary = getExtensionDataDictionary(o);
|
||||
if (dictionary == null)
|
||||
return null;
|
||||
|
||||
return (IEnumerable<KeyValuePair<object, object>>)createEnumerableWrapper(null, dictionary);
|
||||
};
|
||||
|
||||
if (extensionDataAttribute.ReadData)
|
||||
contract.ExtensionDataSetter = extensionDataSetter;
|
||||
|
||||
if (extensionDataAttribute.WriteData)
|
||||
contract.ExtensionDataGetter = extensionDataGetter;
|
||||
}
|
||||
|
||||
internal struct DictionaryEnumerator<TEnumeratorKey, TEnumeratorValue> : IEnumerable<KeyValuePair<object, object>>, IEnumerator<KeyValuePair<object, object>>
|
||||
{
|
||||
private readonly IEnumerator<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> _e;
|
||||
|
||||
public DictionaryEnumerator(IEnumerable<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> e)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(e, "e");
|
||||
_e = e.GetEnumerator();
|
||||
}
|
||||
|
||||
return extensionDataSetter;
|
||||
public bool MoveNext()
|
||||
{
|
||||
return _e.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_e.Reset();
|
||||
}
|
||||
|
||||
public KeyValuePair<object, object> Current
|
||||
{
|
||||
get { return new KeyValuePair<object, object>(_e.Current.Key, _e.Current.Value); }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_e.Dispose();
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get { return Current; }
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private ConstructorInfo GetAttributeConstructor(Type objectType)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
@@ -70,7 +71,13 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <param name="o">The object to set extension data on.</param>
|
||||
/// <param name="key">The extension data key.</param>
|
||||
/// <param name="value">The extension data value.</param>
|
||||
public delegate void ExtensionDataSetter(object o, string key, JToken value);
|
||||
public delegate void ExtensionDataSetter(object o, string key, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets extension data for an object during serialization.
|
||||
/// </summary>
|
||||
/// <param name="o">The object to set extension data on.</param>
|
||||
public delegate IEnumerable<KeyValuePair<object, object>> ExtensionDataGetter(object o);
|
||||
|
||||
/// <summary>
|
||||
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
|
||||
|
||||
@@ -81,6 +81,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
public ExtensionDataSetter ExtensionDataSetter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the extension data getter.
|
||||
/// </summary>
|
||||
public ExtensionDataGetter ExtensionDataGetter { get; set; }
|
||||
|
||||
private bool? _hasRequiredOrDefaultValueProperties;
|
||||
internal bool HasRequiredOrDefaultValueProperties
|
||||
{
|
||||
|
||||
@@ -1733,7 +1733,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
if (!reader.Read())
|
||||
break;
|
||||
|
||||
SetExtensionData(contract, reader, memberName, newObject);
|
||||
SetExtensionData(contract, member, reader, memberName, newObject);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1749,7 +1749,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
// set extension data if property is ignored or readonly
|
||||
if (!SetPropertyValue(property, propertyConverter, contract, member, reader, newObject))
|
||||
SetExtensionData(contract, reader, memberName, newObject);
|
||||
SetExtensionData(contract, member, reader, memberName, newObject);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1780,15 +1780,15 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
return newObject;
|
||||
}
|
||||
|
||||
private void SetExtensionData(JsonObjectContract contract, JsonReader reader, string memberName, object o)
|
||||
private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o)
|
||||
{
|
||||
if (contract.ExtensionDataSetter != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
JToken extensionDataValue = JToken.ReadFrom(reader);
|
||||
object value = CreateValueInternal(reader, null, null, null, contract, member, null);
|
||||
|
||||
contract.ExtensionDataSetter(o, memberName, extensionDataValue);
|
||||
contract.ExtensionDataSetter(o, memberName, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -393,6 +393,37 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
if (contract.ExtensionDataGetter != null)
|
||||
{
|
||||
IEnumerable<KeyValuePair<object, object>> extensionData = contract.ExtensionDataGetter(value);
|
||||
if (extensionData != null)
|
||||
{
|
||||
foreach (KeyValuePair<object, object> e in extensionData)
|
||||
{
|
||||
JsonContract keyContract = GetContractSafe(e.Key);
|
||||
JsonContract valueContract = GetContractSafe(e.Value);
|
||||
|
||||
bool escape;
|
||||
string propertyName = GetPropertyName(writer, e.Key, keyContract, out escape);
|
||||
|
||||
if (ShouldWriteReference(e.Value, null, valueContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(propertyName);
|
||||
WriteReference(writer, e.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CheckForCircularReference(writer, e.Value, null, valueContract, contract, member))
|
||||
continue;
|
||||
|
||||
writer.WritePropertyName(propertyName);
|
||||
|
||||
SerializeValue(writer, e.Value, valueContract, null, contract, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
|
||||
_serializeStack.RemoveAt(_serializeStack.Count - 1);
|
||||
@@ -854,7 +885,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
foreach (DictionaryEntry entry in values)
|
||||
{
|
||||
bool escape;
|
||||
string propertyName = GetPropertyName(writer, entry, contract.KeyContract, out escape);
|
||||
string propertyName = GetPropertyName(writer, entry.Key, contract.KeyContract, out escape);
|
||||
|
||||
propertyName = (contract.PropertyNameResolver != null)
|
||||
? contract.PropertyNameResolver(propertyName)
|
||||
@@ -896,20 +927,18 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
OnSerialized(writer, contract, underlyingDictionary);
|
||||
}
|
||||
|
||||
private string GetPropertyName(JsonWriter writer, DictionaryEntry entry, JsonContract contract, out bool escape)
|
||||
private string GetPropertyName(JsonWriter writer, object name, JsonContract contract, out bool escape)
|
||||
{
|
||||
object key = entry.Key;
|
||||
|
||||
string propertyName;
|
||||
|
||||
JsonPrimitiveContract primitiveContract = contract as JsonPrimitiveContract;
|
||||
if (primitiveContract != null)
|
||||
if (contract.ContractType == JsonContractType.Primitive)
|
||||
{
|
||||
JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;
|
||||
if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTime || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeNullable)
|
||||
{
|
||||
escape = false;
|
||||
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
|
||||
DateTimeUtils.WriteDateTimeString(sw, (DateTime)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
|
||||
DateTimeUtils.WriteDateTimeString(sw, (DateTime)name, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
|
||||
return sw.ToString();
|
||||
}
|
||||
#if !NET20
|
||||
@@ -917,17 +946,17 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
{
|
||||
escape = false;
|
||||
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
|
||||
DateTimeUtils.WriteDateTimeOffsetString(sw, (DateTimeOffset)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
|
||||
DateTimeUtils.WriteDateTimeOffsetString(sw, (DateTimeOffset)name, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
|
||||
return sw.ToString();
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
escape = true;
|
||||
return Convert.ToString(key, CultureInfo.InvariantCulture);
|
||||
return Convert.ToString(name, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
else if (TryConvertToString(key, key.GetType(), out propertyName))
|
||||
else if (TryConvertToString(name, name.GetType(), out propertyName))
|
||||
{
|
||||
escape = true;
|
||||
return propertyName;
|
||||
@@ -935,7 +964,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
else
|
||||
{
|
||||
escape = true;
|
||||
return key.ToString();
|
||||
return name.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,10 @@ namespace Newtonsoft.Json.Utilities
|
||||
else
|
||||
callExpression = Expression.Block(callExpression, Expression.Constant(null));
|
||||
}
|
||||
else
|
||||
{
|
||||
callExpression = EnsureCastExpression(callExpression, type);
|
||||
}
|
||||
|
||||
LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall<T, object>), callExpression, targetParameterExpression, argsParameterExpression);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user