-Added XmlSerializer style Specified property support

This commit is contained in:
JamesNK
2010-11-25 08:17:22 +00:00
parent efc2310a3d
commit 2eb0d3bf48
7 changed files with 192 additions and 10 deletions
@@ -3378,6 +3378,138 @@ keyword such as type of business.""
Console.WriteLine(json);
}
public class SpecifiedTestClass
{
private bool _nameSpecified;
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
// dummy. should never be used because it isn't of type bool
[JsonIgnore]
public long AgeSpecified { get; set; }
[JsonIgnore]
public bool NameSpecified
{
get { return _nameSpecified; }
set { _nameSpecified = value; }
}
[JsonIgnore]
public bool WeightSpecified;
}
[Test]
public void SpecifiedTest()
{
SpecifiedTestClass c = new SpecifiedTestClass();
c.Name = "James";
c.Age = 27;
c.NameSpecified = false;
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
Assert.AreEqual(@"{
""Age"": 27
}", json);
SpecifiedTestClass deserialized = JsonConvert.DeserializeObject<SpecifiedTestClass>(json);
Assert.IsNull(deserialized.Name);
Assert.IsFalse(deserialized.NameSpecified);
Assert.IsFalse(deserialized.WeightSpecified);
Assert.AreEqual(27, deserialized.Age);
c.NameSpecified = true;
c.WeightSpecified = true;
json = JsonConvert.SerializeObject(c, Formatting.Indented);
Assert.AreEqual(@"{
""Name"": ""James"",
""Age"": 27,
""Weight"": 0
}", json);
deserialized = JsonConvert.DeserializeObject<SpecifiedTestClass>(json);
Assert.AreEqual("James", deserialized.Name);
Assert.IsTrue(deserialized.NameSpecified);
Assert.IsTrue(deserialized.WeightSpecified);
Assert.AreEqual(27, deserialized.Age);
// XmlSerializer s = new XmlSerializer(typeof(OptionalOrder));
// StringWriter sw = new StringWriter();
// s.Serialize(sw, new OptionalOrder() { FirstOrder = "First", FirstOrderSpecified = true});
// Console.WriteLine(sw.ToString());
// string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
//<OptionalOrder xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
// <FirstOrder>First</FirstOrder>
//</OptionalOrder>";
// OptionalOrder o = (OptionalOrder)s.Deserialize(new StringReader(xml));
// Console.WriteLine(o.FirstOrder);
// Console.WriteLine(o.FirstOrderSpecified);
}
//public class OptionalOrder
//{
// // This field shouldn't be serialized
// // if it is uninitialized.
// public string FirstOrder;
// // Use the XmlIgnoreAttribute to ignore the
// // special field named "FirstOrderSpecified".
// [System.Xml.Serialization.XmlIgnoreAttribute]
// public bool FirstOrderSpecified;
//}
public class FamilyDetails
{
public string Name { get; set; }
public int NumberOfChildren { get; set; }
[JsonIgnore]
public bool NumberOfChildrenSpecified { get; set; }
}
[Test]
public void SpecifiedExample()
{
FamilyDetails joe = new FamilyDetails();
joe.Name = "Joe Family Details";
joe.NumberOfChildren = 4;
joe.NumberOfChildrenSpecified = true;
FamilyDetails martha = new FamilyDetails();
martha.Name = "Martha Family Details";
martha.NumberOfChildren = 3;
martha.NumberOfChildrenSpecified = false;
string json = JsonConvert.SerializeObject(new[] { joe, martha }, Formatting.Indented);
//[
// {
// "Name": "Joe Family Details",
// "NumberOfChildren": 4
// },
// {
// "Name": "Martha Family Details"
// }
//]
Console.WriteLine(json);
string mikeString = "{\"Name\": \"Mike Person\"}";
FamilyDetails mike = JsonConvert.DeserializeObject<FamilyDetails>(mikeString);
Console.WriteLine("mikeString specifies number of children: {0}", mike.NumberOfChildrenSpecified);
string mikeFullDisclosureString = "{\"Name\": \"Mike Person\", \"NumberOfChildren\": \"0\"}";
mike = JsonConvert.DeserializeObject<FamilyDetails>(mikeFullDisclosureString);
Console.WriteLine("mikeString specifies number of children: {0}", mike.NumberOfChildrenSpecified);
}
public class DictionaryKey
{
public string Value { get; set; }
@@ -361,7 +361,8 @@ namespace Newtonsoft.Json.Schema
{
bool optional = property.NullValueHandling == NullValueHandling.Ignore ||
property.DefaultValueHandling == DefaultValueHandling.Ignore ||
property.ShouldSerialize != null;
property.ShouldSerialize != null ||
property.GetIsSpecified != null;
JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required, optional);
@@ -35,6 +35,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Xml.Serialization;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Linq;
@@ -717,6 +718,8 @@ namespace Newtonsoft.Json.Serialization
property.ShouldSerialize = CreateShouldSerializeTest(member);
SetIsSpecifiedActions(property, member);
return property;
}
@@ -733,6 +736,25 @@ namespace Newtonsoft.Json.Serialization
return o => (bool) shouldSerializeCall(o);
}
private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member)
{
MemberInfo specifiedMember = member.DeclaringType.GetProperty(member.Name + JsonTypeReflector.SpecifiedPostfix);
if (specifiedMember == null)
specifiedMember = member.DeclaringType.GetField(member.Name + JsonTypeReflector.SpecifiedPostfix);
if (specifiedMember == null || ReflectionUtils.GetMemberUnderlyingType(specifiedMember) != typeof(bool)
|| (ReflectionUtils.GetAttribute<XmlIgnoreAttribute>(specifiedMember) != null
&& ReflectionUtils.GetAttribute<JsonIgnoreAttribute>(specifiedMember) != null))
{
return;
}
Func<object, object> specifiedPropertyGet = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(specifiedMember);
property.GetIsSpecified = o => (bool)specifiedPropertyGet(o);
property.SetIsSpecified = JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(specifiedMember);
}
/// <summary>
/// Resolves the name of the property.
/// </summary>
@@ -137,6 +137,18 @@ namespace Newtonsoft.Json.Serialization
/// <value>A predicate used to determine whether the property should be serialize.</value>
public Predicate<object> ShouldSerialize { get; set; }
/// <summary>
/// Gets or sets a predicate used to determine whether the property should be serialized.
/// </summary>
/// <value>A predicate used to determine whether the property should be serialized.</value>
public Predicate<object> GetIsSpecified { get; set; }
/// <summary>
/// Gets or sets an action used to set whether the property has been deserialized.
/// </summary>
/// <value>An action used to set whether the property has been deserialized.</value>
public Action<object, object> SetIsSpecified { get; set; }
/// <summary>
/// Returns a <see cref="String"/> that represents this instance.
/// </summary>
@@ -552,7 +552,12 @@ namespace Newtonsoft.Json.Serialization
// this could happen because of a JsonConverter against the type
if ((!useExistingValue || value != currentValue)
&& ShouldSetPropertyValue(property, value))
{
property.ValueProvider.SetValue(target, value);
if (property.SetIsSpecified != null)
property.SetIsSpecified(target, true);
}
}
private bool ShouldSetPropertyValue(JsonProperty property, object value)
@@ -57,7 +57,8 @@ namespace Newtonsoft.Json.Serialization
}
}
public JsonSerializerInternalWriter(JsonSerializer serializer) : base(serializer)
public JsonSerializerInternalWriter(JsonSerializer serializer)
: base(serializer)
{
}
@@ -109,7 +110,7 @@ namespace Newtonsoft.Json.Serialization
}
else if (valueContract is JsonStringContract)
{
SerializeString(writer, value, (JsonStringContract) valueContract);
SerializeString(writer, value, (JsonStringContract)valueContract);
}
else if (valueContract is JsonObjectContract)
{
@@ -117,12 +118,12 @@ namespace Newtonsoft.Json.Serialization
}
else if (valueContract is JsonDictionaryContract)
{
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) valueContract;
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)valueContract;
SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, collectionValueContract);
}
else if (valueContract is JsonArrayContract)
{
JsonArrayContract arrayContract = (JsonArrayContract) valueContract;
JsonArrayContract arrayContract = (JsonArrayContract)valueContract;
SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, collectionValueContract);
}
else if (valueContract is JsonLinqContract)
@@ -132,13 +133,13 @@ namespace Newtonsoft.Json.Serialization
#if !SILVERLIGHT && !PocketPC
else if (valueContract is JsonISerializableContract)
{
SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) valueContract);
SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract);
}
#endif
#if !(NET35 || NET20 || SILVERLIGHT)
else if (valueContract is JsonDynamicContract)
{
SerializeDynamic(writer, (IDynamicMetaObjectProvider) value, (JsonDynamicContract) valueContract);
SerializeDynamic(writer, (IDynamicMetaObjectProvider)value, (JsonDynamicContract)valueContract);
}
#endif
}
@@ -242,9 +243,9 @@ namespace Newtonsoft.Json.Serialization
// use the objectType's TypeConverter if it has one and can convert to a string
if (converter != null
#if !SILVERLIGHT
&& !(converter is ComponentConverter)
&& !(converter is ComponentConverter)
#endif
&& converter.GetType() != typeof(TypeConverter))
&& converter.GetType() != typeof(TypeConverter))
{
if (converter.CanConvertTo(typeof(string)))
{
@@ -311,7 +312,7 @@ namespace Newtonsoft.Json.Serialization
{
try
{
if (!property.Ignored && property.Readable && ShouldSerialize(property, value))
if (!property.Ignored && property.Readable && ShouldSerialize(property, value) && IsSpecified(property, value))
{
object memberValue = property.ValueProvider.GetValue(value);
JsonContract memberContract = GetContractSafe(memberValue);
@@ -610,5 +611,13 @@ namespace Newtonsoft.Json.Serialization
return property.ShouldSerialize(target);
}
private bool IsSpecified(JsonProperty property, object target)
{
if (property.GetIsSpecified == null)
return true;
return property.GetIsSpecified(target);
}
}
}
@@ -49,6 +49,7 @@ namespace Newtonsoft.Json.Serialization
public const string ArrayValuesPropertyName = "$values";
public const string ShouldSerializePrefix = "ShouldSerialize";
public const string SpecifiedPostfix = "Specified";
private static readonly ThreadSafeStore<ICustomAttributeProvider, Type> JsonConverterTypeCache = new ThreadSafeStore<ICustomAttributeProvider, Type>(GetJsonConverterTypeFromAttribute);
#if !SILVERLIGHT && !PocketPC && !NET20