diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 9eb401c7..8cb2dd3b 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -4691,6 +4691,7 @@ keyword such as type of business."" public Boolean WheelchairAccessible { get; set; } } + [Test] public void DeserializeGenericEnumerableProperty() { BusRun r = JsonConvert.DeserializeObject("{\"Departures\":[\"\\/Date(1309874148734-0400)\\/\",\"\\/Date(1309874148739-0400)\\/\",null],\"WheelchairAccessible\":true}"); @@ -4700,5 +4701,52 @@ keyword such as type of business."" Assert.IsNotNull(r.Departures.ElementAt(1)); Assert.IsNull(r.Departures.ElementAt(2)); } + +#if !(NET20) + [DataContract] + public class BaseType + { + + [DataMember] + public string zebra; + } + + [DataContract] + public class DerivedType : BaseType + { + [DataMember(Order = 0)] + public string bird; + [DataMember(Order = 1)] + public string parrot; + [DataMember] + public string dog; + [DataMember(Order = 3)] + public string antelope; + [DataMember] + public string cat; + [JsonProperty(Order = 1)] + public string albatross; + [JsonProperty(Order = -2)] + public string dinosaur; + } + + [Test] + public void JsonPropertyDataMemberOrder() + { + DerivedType d = new DerivedType(); + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"{ + ""dinosaur"": null, + ""dog"": null, + ""cat"": null, + ""zebra"": null, + ""bird"": null, + ""parrot"": null, + ""albatross"": null, + ""antelope"": null +}", json); + } +#endif } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs index 465d2d51..b283c585 100644 --- a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs +++ b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs @@ -16,6 +16,7 @@ namespace Newtonsoft.Json internal ObjectCreationHandling? _objectCreationHandling; internal TypeNameHandling? _typeNameHandling; internal bool? _isReference; + internal int? _order; /// /// Gets or sets the null value handling used when serializing this property. @@ -77,6 +78,16 @@ namespace Newtonsoft.Json set { _isReference = value; } } + /// + /// Gets or sets the order of serialization and deserialization of a member. + /// + /// The numeric order of serialization or deserialization. + public int Order + { + get { return _order ?? default(int); } + set { _order = value; } + } + /// /// Gets or sets the name of the property. /// diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 12962617..48e028cc 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -753,7 +753,8 @@ namespace Newtonsoft.Json.Serialization properties.AddProperty(property); } - return properties; + IList orderedProperties = properties.OrderBy(p => p.Order ?? -1).ToList(); + return orderedProperties; } /// @@ -830,13 +831,21 @@ namespace Newtonsoft.Json.Serialization property.UnderlyingName = name; if (propertyAttribute != null) + { property.Required = propertyAttribute.Required; + property.Order = propertyAttribute._order; + } #if !PocketPC && !NET20 else if (dataMemberAttribute != null) + { property.Required = (dataMemberAttribute.IsRequired) ? Required.AllowNull : Required.Default; + property.Order = (dataMemberAttribute.Order != -1) ? (int?) dataMemberAttribute.Order : null; + } #endif else + { property.Required = Required.Default; + } property.Ignored = (hasIgnoreAttribute || (memberSerialization == MemberSerialization.OptIn diff --git a/Src/Newtonsoft.Json/Serialization/JsonProperty.cs b/Src/Newtonsoft.Json/Serialization/JsonProperty.cs index ccc39d0f..322eb5cf 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonProperty.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonProperty.cs @@ -38,6 +38,12 @@ namespace Newtonsoft.Json.Serialization /// The name of the property. public string PropertyName { get; set; } + /// + /// Gets or sets the order of serialization and deserialization of a member. + /// + /// The numeric order of serialization or deserialization. + public int? Order { get; set; } + /// /// Gets or sets the name of the underlying member or parameter. ///