-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);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private Func<object> GetDefaultCreator(Type createdType)
|
||||
{
|
||||
return JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(createdType);
|
||||
return JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(createdType);
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
@@ -670,9 +670,24 @@ namespace Newtonsoft.Json.Serialization
|
||||
property.ObjectCreationHandling = (propertyAttribute != null) ? propertyAttribute._objectCreationHandling : null;
|
||||
property.IsReference = (propertyAttribute != null) ? propertyAttribute._isReference : null;
|
||||
|
||||
property.ShouldSerialize = CreateShouldSerializeTest(member);
|
||||
|
||||
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>
|
||||
/// Resolves the name of the property.
|
||||
/// </summary>
|
||||
|
||||
@@ -38,10 +38,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
internal Type CollectionItemType { get; private set; }
|
||||
|
||||
private bool _isCollectionItemTypeNullableType;
|
||||
private Type _genericCollectionDefinitionType;
|
||||
private readonly bool _isCollectionItemTypeNullableType;
|
||||
private readonly Type _genericCollectionDefinitionType;
|
||||
private Type _genericWrapperType;
|
||||
private MethodCall<object> _genericWrapperCreator;
|
||||
private MethodCall<object, object> _genericWrapperCreator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
|
||||
@@ -78,7 +78,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType);
|
||||
|
||||
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor);
|
||||
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(genericWrapperConstructor);
|
||||
}
|
||||
|
||||
return (IWrappedCollection)_genericWrapperCreator(null, list);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private readonly Type _genericCollectionDefinitionType;
|
||||
private Type _genericWrapperType;
|
||||
private MethodCall<object> _genericWrapperCreator;
|
||||
private MethodCall<object, object> _genericWrapperCreator;
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
|
||||
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor);
|
||||
_genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(genericWrapperConstructor);
|
||||
}
|
||||
|
||||
return (IWrappedDictionary)_genericWrapperCreator(null, dictionary);
|
||||
|
||||
@@ -125,6 +125,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <value>The object creation handling.</value>
|
||||
public ObjectCreationHandling? ObjectCreationHandling { get; set; }
|
||||
|
||||
public Predicate<object> ShouldSerialize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="String"/> that represents this instance.
|
||||
/// </summary>
|
||||
|
||||
@@ -753,9 +753,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (property != null)
|
||||
{
|
||||
if (!property.Ignored)
|
||||
{
|
||||
propertyValues[property] = CreateValueProperty(reader, property, null, true, null);
|
||||
}
|
||||
else
|
||||
reader.Skip();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -311,7 +311,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!property.Ignored && property.Readable)
|
||||
if (!property.Ignored && property.Readable && ShouldSerialize(property, value))
|
||||
{
|
||||
object memberValue = property.ValueProvider.GetValue(value);
|
||||
JsonContract memberContract = GetContractSafe(memberValue);
|
||||
@@ -547,5 +547,13 @@ namespace Newtonsoft.Json.Serialization
|
||||
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 ArrayValuesPropertyName = "$values";
|
||||
|
||||
public const string ShouldSerializePrefix = "ShouldSerialize";
|
||||
|
||||
private static readonly ThreadSafeStore<ICustomAttributeProvider, Type> JsonConverterTypeCache = new ThreadSafeStore<ICustomAttributeProvider, Type>(GetJsonConverterTypeFromAttribute);
|
||||
#if !SILVERLIGHT && !PocketPC && !NET20
|
||||
private static readonly ThreadSafeStore<Type, Type> AssociatedMetadataTypesCache = new ThreadSafeStore<Type, Type>(GetAssociateMetadataTypeFromAttribute);
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
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);
|
||||
ILGenerator generator = dynamicMethod.GetILGenerator();
|
||||
@@ -94,10 +94,10 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
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.InitLocals = true;
|
||||
@@ -123,7 +123,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
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)
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
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;
|
||||
if (c != null)
|
||||
@@ -42,14 +42,14 @@ namespace Newtonsoft.Json.Utilities
|
||||
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)
|
||||
return () => ReflectionUtils.CreateInstance(type);
|
||||
return () => (T)ReflectionUtils.CreateInstance(type);
|
||||
|
||||
ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true);
|
||||
|
||||
return () => constructorInfo.Invoke(null);
|
||||
return () => (T)constructorInfo.Invoke(null);
|
||||
}
|
||||
|
||||
public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public abstract MethodCall<object> CreateMethodCall(MethodBase method);
|
||||
public abstract Func<object> CreateDefaultConstructor(Type type);
|
||||
public abstract MethodCall<T, object> CreateMethodCall<T>(MethodBase method);
|
||||
public abstract Func<T> CreateDefaultConstructor<T>(Type type);
|
||||
public abstract Func<T, object> CreateGet<T>(PropertyInfo propertyInfo);
|
||||
public abstract Func<T, object> CreateGet<T>(FieldInfo fieldInfo);
|
||||
public abstract Action<T, object> CreateSet<T>(FieldInfo fieldInfo);
|
||||
|
||||
Reference in New Issue
Block a user