-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:
JamesNK
2010-03-20 09:16:24 +00:00
parent d393430f30
commit 408a407105
13 changed files with 120 additions and 23 deletions
@@ -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)
+1 -1
View File
@@ -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);