-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); 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)
+1 -1
View File
@@ -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);