-Added support for ShouldSerialize conditional methods
-Fixed not correctly skipping ignored JSON properties when deserializing via a non-default constructor
This commit is contained in:
@@ -3247,5 +3247,74 @@ keyword such as type of business.""
|
|||||||
var json = JsonConvert.SerializeObject(child);
|
var json = JsonConvert.SerializeObject(child);
|
||||||
JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
|
JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ConstructorCompexIgnoredProperty
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public Product Ignored { get; set; }
|
||||||
|
public string First { get; set; }
|
||||||
|
public int Second { get; set; }
|
||||||
|
|
||||||
|
public ConstructorCompexIgnoredProperty(string first, int second)
|
||||||
|
{
|
||||||
|
First = first;
|
||||||
|
Second = second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DeserializeIgnoredPropertyInConstructor()
|
||||||
|
{
|
||||||
|
string json = @"{""First"":""First"",""Second"":2,""Ignored"":{""Name"":""James""},""AdditionalContent"":{""LOL"":true}}";
|
||||||
|
|
||||||
|
ConstructorCompexIgnoredProperty cc = JsonConvert.DeserializeObject<ConstructorCompexIgnoredProperty>(json);
|
||||||
|
Assert.AreEqual("First", cc.First);
|
||||||
|
Assert.AreEqual(2, cc.Second);
|
||||||
|
Assert.AreEqual(null, cc.Ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ShouldSerializeTestClass
|
||||||
|
{
|
||||||
|
internal bool _shouldSerializeName;
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Age { get; set; }
|
||||||
|
|
||||||
|
public void ShouldSerializeAge()
|
||||||
|
{
|
||||||
|
// dummy. should never be used because it doesn't return bool
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldSerializeName()
|
||||||
|
{
|
||||||
|
return _shouldSerializeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldSerializeTest()
|
||||||
|
{
|
||||||
|
ShouldSerializeTestClass c = new ShouldSerializeTestClass();
|
||||||
|
c.Name = "James";
|
||||||
|
c.Age = 27;
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
|
||||||
|
|
||||||
|
Assert.AreEqual(@"{
|
||||||
|
""Age"": 27
|
||||||
|
}", json);
|
||||||
|
|
||||||
|
c._shouldSerializeName = true;
|
||||||
|
json = JsonConvert.SerializeObject(c, Formatting.Indented);
|
||||||
|
|
||||||
|
Assert.AreEqual(@"{
|
||||||
|
""Name"": ""James"",
|
||||||
|
""Age"": 27
|
||||||
|
}", json);
|
||||||
|
|
||||||
|
ShouldSerializeTestClass deserialized = JsonConvert.DeserializeObject<ShouldSerializeTestClass>(json);
|
||||||
|
Assert.AreEqual("James", deserialized.Name);
|
||||||
|
Assert.AreEqual(27, deserialized.Age);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +360,8 @@ namespace Newtonsoft.Json.Schema
|
|||||||
if (!property.Ignored)
|
if (!property.Ignored)
|
||||||
{
|
{
|
||||||
bool optional = property.NullValueHandling == NullValueHandling.Ignore ||
|
bool optional = property.NullValueHandling == NullValueHandling.Ignore ||
|
||||||
property.DefaultValueHandling == DefaultValueHandling.Ignore;
|
property.DefaultValueHandling == DefaultValueHandling.Ignore ||
|
||||||
|
property.ShouldSerialize != null;
|
||||||
|
|
||||||
JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required, optional);
|
JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required, optional);
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
|
|
||||||
private Func<object> GetDefaultCreator(Type createdType)
|
private Func<object> GetDefaultCreator(Type createdType)
|
||||||
{
|
{
|
||||||
return JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(createdType);
|
return JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(createdType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeContract(JsonContract contract)
|
private void InitializeContract(JsonContract contract)
|
||||||
@@ -419,7 +419,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
ConstructorInfo constructorInfo = objectType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new [] {typeof (SerializationInfo), typeof (StreamingContext)}, null);
|
ConstructorInfo constructorInfo = objectType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new [] {typeof (SerializationInfo), typeof (StreamingContext)}, null);
|
||||||
if (constructorInfo != null)
|
if (constructorInfo != null)
|
||||||
{
|
{
|
||||||
MethodCall<object> methodCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(constructorInfo);
|
MethodCall<object, object> methodCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(constructorInfo);
|
||||||
|
|
||||||
contract.ISerializableCreator = (args => methodCall(null, args));
|
contract.ISerializableCreator = (args => methodCall(null, args));
|
||||||
}
|
}
|
||||||
@@ -670,9 +670,24 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
property.ObjectCreationHandling = (propertyAttribute != null) ? propertyAttribute._objectCreationHandling : null;
|
property.ObjectCreationHandling = (propertyAttribute != null) ? propertyAttribute._objectCreationHandling : null;
|
||||||
property.IsReference = (propertyAttribute != null) ? propertyAttribute._isReference : null;
|
property.IsReference = (propertyAttribute != null) ? propertyAttribute._isReference : null;
|
||||||
|
|
||||||
|
property.ShouldSerialize = CreateShouldSerializeTest(member);
|
||||||
|
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Predicate<object> CreateShouldSerializeTest(MemberInfo member)
|
||||||
|
{
|
||||||
|
MethodInfo shouldSerializeMethod = member.DeclaringType.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, new Type[0]);
|
||||||
|
|
||||||
|
if (shouldSerializeMethod == null || shouldSerializeMethod.ReturnType != typeof(bool))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
MethodCall<object, object> shouldSerializeCall =
|
||||||
|
JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(shouldSerializeMethod);
|
||||||
|
|
||||||
|
return o => (bool) shouldSerializeCall(o);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolves the name of the property.
|
/// Resolves the name of the property.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
{
|
{
|
||||||
internal Type CollectionItemType { get; private set; }
|
internal Type CollectionItemType { get; private set; }
|
||||||
|
|
||||||
private bool _isCollectionItemTypeNullableType;
|
private readonly bool _isCollectionItemTypeNullableType;
|
||||||
private Type _genericCollectionDefinitionType;
|
private readonly Type _genericCollectionDefinitionType;
|
||||||
private Type _genericWrapperType;
|
private Type _genericWrapperType;
|
||||||
private MethodCall<object> _genericWrapperCreator;
|
private MethodCall<object, object> _genericWrapperCreator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
|
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
|
||||||
@@ -78,7 +78,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType);
|
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType);
|
||||||
|
|
||||||
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||||
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor);
|
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(genericWrapperConstructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (IWrappedCollection)_genericWrapperCreator(null, list);
|
return (IWrappedCollection)_genericWrapperCreator(null, list);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
|
|
||||||
private readonly Type _genericCollectionDefinitionType;
|
private readonly Type _genericCollectionDefinitionType;
|
||||||
private Type _genericWrapperType;
|
private Type _genericWrapperType;
|
||||||
private MethodCall<object> _genericWrapperCreator;
|
private MethodCall<object, object> _genericWrapperCreator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
|
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
|
||||||
@@ -81,7 +81,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(DictionaryWrapper<,>), DictionaryKeyType, DictionaryValueType);
|
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(DictionaryWrapper<,>), DictionaryKeyType, DictionaryValueType);
|
||||||
|
|
||||||
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||||
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor);
|
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(genericWrapperConstructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (IWrappedDictionary)_genericWrapperCreator(null, dictionary);
|
return (IWrappedDictionary)_genericWrapperCreator(null, dictionary);
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
/// <value>The object creation handling.</value>
|
/// <value>The object creation handling.</value>
|
||||||
public ObjectCreationHandling? ObjectCreationHandling { get; set; }
|
public ObjectCreationHandling? ObjectCreationHandling { get; set; }
|
||||||
|
|
||||||
|
public Predicate<object> ShouldSerialize { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="String"/> that represents this instance.
|
/// Returns a <see cref="String"/> that represents this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -753,9 +753,9 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
if (property != null)
|
if (property != null)
|
||||||
{
|
{
|
||||||
if (!property.Ignored)
|
if (!property.Ignored)
|
||||||
{
|
|
||||||
propertyValues[property] = CreateValueProperty(reader, property, null, true, null);
|
propertyValues[property] = CreateValueProperty(reader, property, null, true, null);
|
||||||
}
|
else
|
||||||
|
reader.Skip();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!property.Ignored && property.Readable)
|
if (!property.Ignored && property.Readable && ShouldSerialize(property, value))
|
||||||
{
|
{
|
||||||
object memberValue = property.ValueProvider.GetValue(value);
|
object memberValue = property.ValueProvider.GetValue(value);
|
||||||
JsonContract memberContract = GetContractSafe(memberValue);
|
JsonContract memberContract = GetContractSafe(memberValue);
|
||||||
@@ -547,5 +547,13 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
writer.WriteEnd();
|
writer.WriteEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ShouldSerialize(JsonProperty property, object target)
|
||||||
|
{
|
||||||
|
if (property.ShouldSerialize == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return property.ShouldSerialize(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,6 +48,8 @@ namespace Newtonsoft.Json.Serialization
|
|||||||
public const string TypePropertyName = "$type";
|
public const string TypePropertyName = "$type";
|
||||||
public const string ArrayValuesPropertyName = "$values";
|
public const string ArrayValuesPropertyName = "$values";
|
||||||
|
|
||||||
|
public const string ShouldSerializePrefix = "ShouldSerialize";
|
||||||
|
|
||||||
private static readonly ThreadSafeStore<ICustomAttributeProvider, Type> JsonConverterTypeCache = new ThreadSafeStore<ICustomAttributeProvider, Type>(GetJsonConverterTypeFromAttribute);
|
private static readonly ThreadSafeStore<ICustomAttributeProvider, Type> JsonConverterTypeCache = new ThreadSafeStore<ICustomAttributeProvider, Type>(GetJsonConverterTypeFromAttribute);
|
||||||
#if !SILVERLIGHT && !PocketPC && !NET20
|
#if !SILVERLIGHT && !PocketPC && !NET20
|
||||||
private static readonly ThreadSafeStore<Type, Type> AssociatedMetadataTypesCache = new ThreadSafeStore<Type, Type>(GetAssociateMetadataTypeFromAttribute);
|
private static readonly ThreadSafeStore<Type, Type> AssociatedMetadataTypesCache = new ThreadSafeStore<Type, Type>(GetAssociateMetadataTypeFromAttribute);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
return dynamicMethod;
|
return dynamicMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override MethodCall<object> CreateMethodCall(MethodBase method)
|
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
|
||||||
{
|
{
|
||||||
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType);
|
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType);
|
||||||
ILGenerator generator = dynamicMethod.GetILGenerator();
|
ILGenerator generator = dynamicMethod.GetILGenerator();
|
||||||
@@ -94,10 +94,10 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
|
|
||||||
generator.Return();
|
generator.Return();
|
||||||
|
|
||||||
return (MethodCall<object>)dynamicMethod.CreateDelegate(typeof(MethodCall<object>));
|
return (MethodCall<T, object>)dynamicMethod.CreateDelegate(typeof(MethodCall<T, object>));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Func<object> CreateDefaultConstructor(Type type)
|
public override Func<T> CreateDefaultConstructor<T>(Type type)
|
||||||
{
|
{
|
||||||
DynamicMethod dynamicMethod = CreateDynamicMethod("Create" + type.FullName, typeof(object), Type.EmptyTypes, type);
|
DynamicMethod dynamicMethod = CreateDynamicMethod("Create" + type.FullName, typeof(object), Type.EmptyTypes, type);
|
||||||
dynamicMethod.InitLocals = true;
|
dynamicMethod.InitLocals = true;
|
||||||
@@ -123,7 +123,7 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
|
|
||||||
generator.Return();
|
generator.Return();
|
||||||
|
|
||||||
return (Func<object>)dynamicMethod.CreateDelegate(typeof(Func<object>));
|
return (Func<T>)dynamicMethod.CreateDelegate(typeof(Func<T>));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
|
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
{
|
{
|
||||||
public static readonly LateBoundReflectionDelegateFactory Instance = new LateBoundReflectionDelegateFactory();
|
public static readonly LateBoundReflectionDelegateFactory Instance = new LateBoundReflectionDelegateFactory();
|
||||||
|
|
||||||
public override MethodCall<object> CreateMethodCall(MethodBase method)
|
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
|
||||||
{
|
{
|
||||||
ConstructorInfo c = method as ConstructorInfo;
|
ConstructorInfo c = method as ConstructorInfo;
|
||||||
if (c != null)
|
if (c != null)
|
||||||
@@ -42,14 +42,14 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
return (o, a) => method.Invoke(o, a);
|
return (o, a) => method.Invoke(o, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Func<object> CreateDefaultConstructor(Type type)
|
public override Func<T> CreateDefaultConstructor<T>(Type type)
|
||||||
{
|
{
|
||||||
if (type.IsValueType)
|
if (type.IsValueType)
|
||||||
return () => ReflectionUtils.CreateInstance(type);
|
return () => (T)ReflectionUtils.CreateInstance(type);
|
||||||
|
|
||||||
ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true);
|
ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true);
|
||||||
|
|
||||||
return () => constructorInfo.Invoke(null);
|
return () => (T)constructorInfo.Invoke(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
|
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
|
||||||
|
|||||||
@@ -25,5 +25,5 @@
|
|||||||
|
|
||||||
namespace Newtonsoft.Json.Utilities
|
namespace Newtonsoft.Json.Utilities
|
||||||
{
|
{
|
||||||
internal delegate object MethodCall<T>(T target, params object[] args);
|
internal delegate TResult MethodCall<T, TResult>(T target, params object[] args);
|
||||||
}
|
}
|
||||||
@@ -57,8 +57,8 @@ namespace Newtonsoft.Json.Utilities
|
|||||||
throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo));
|
throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract MethodCall<object> CreateMethodCall(MethodBase method);
|
public abstract MethodCall<T, object> CreateMethodCall<T>(MethodBase method);
|
||||||
public abstract Func<object> CreateDefaultConstructor(Type type);
|
public abstract Func<T> CreateDefaultConstructor<T>(Type type);
|
||||||
public abstract Func<T, object> CreateGet<T>(PropertyInfo propertyInfo);
|
public abstract Func<T, object> CreateGet<T>(PropertyInfo propertyInfo);
|
||||||
public abstract Func<T, object> CreateGet<T>(FieldInfo fieldInfo);
|
public abstract Func<T, object> CreateGet<T>(FieldInfo fieldInfo);
|
||||||
public abstract Action<T, object> CreateSet<T>(FieldInfo fieldInfo);
|
public abstract Action<T, object> CreateSet<T>(FieldInfo fieldInfo);
|
||||||
|
|||||||
Reference in New Issue
Block a user