-Added XmlSerializer style Specified property support
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user