From 69594a690f658f5caa0f3828707604e4e9797bf2 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Sat, 19 Nov 2011 07:04:38 +0000 Subject: [PATCH] -Fixed DataTableConverter including nulls with NullValueHandling.Ignore --- .../Converters/DataTableConverterTests.cs | 20 ++++ .../Serialization/TypeNameHandlingTests.cs | 111 ++++++++++++++++++ .../Converters/DataTableConverter.cs | 3 + .../JsonSerializerInternalWriter.cs | 9 +- 4 files changed, 141 insertions(+), 2 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs index dcc93814..0a614e21 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs @@ -154,6 +154,26 @@ namespace Newtonsoft.Json.Tests.Converters + @"{""item"":""shoes"",""price"":null}]", json); } + [Test] + public void SerializeDataTableWithNullAndIgnoreNullHandling() + { + var table = new DataTable(); + table.Columns.Add("item"); + table.Columns.Add("price", typeof(double)); + table.Rows.Add("shirt", 49.99); + table.Rows.Add("pants", 54.99); + table.Rows.Add("shoes"); // no price + + var json = JsonConvert.SerializeObject(table, Formatting.None, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + Assert.AreEqual(@"[" + + @"{""item"":""shirt"",""price"":49.99}," + + @"{""item"":""pants"",""price"":54.99}," + + @"{""item"":""shoes""}]", json); + } + [Test] public void DerializeDataTableWithImplicitNull() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs index 64193804..92b77b57 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs @@ -881,6 +881,55 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual(data, obj.Objects[0]); } + +#if !(WINDOWS_PHONE || SILVERLIGHT) + [Test] + public void ISerializableTypeNameHandlingTest() + { + //Create an instance of our example type + IExample e = new Example("Rob"); + + SerializableWrapper w = new SerializableWrapper + { + Content = e + }; + + //Test Binary Serialization Round Trip + //This will work find because the Binary Formatter serializes type names + //this.TestBinarySerializationRoundTrip(e); + + //Test Json Serialization + //This fails because the JsonSerializer doesn't serialize type names correctly for ISerializable objects + //Type Names should be serialized for All, Auto and Object modes + this.TestJsonSerializationRoundTrip(w, TypeNameHandling.All); + this.TestJsonSerializationRoundTrip(w, TypeNameHandling.Auto); + this.TestJsonSerializationRoundTrip(w, TypeNameHandling.Objects); + } + + private void TestJsonSerializationRoundTrip(SerializableWrapper e, TypeNameHandling flag) + { + Console.WriteLine("Type Name Handling: " + flag.ToString()); + StringWriter writer = new StringWriter(); + + //Create our serializer and set Type Name Handling appropriately + JsonSerializer serializer = new JsonSerializer(); + serializer.TypeNameHandling = flag; + + //Do the actual serialization and dump to Console for inspection + serializer.Serialize(new JsonTextWriter(writer), e); + Console.WriteLine(writer.ToString()); + Console.WriteLine(); + + //Now try to deserialize + //Json.Net will cause an error here as it will try and instantiate + //the interface directly because it failed to respect the + //TypeNameHandling property on serialization + SerializableWrapper f = serializer.Deserialize(new JsonTextReader(new StringReader(writer.ToString()))); + + //Check Round Trip + Assert.AreEqual(e, f, "Objects should be equal after round trip json serialization"); + } +#endif } public class Message @@ -896,4 +945,66 @@ namespace Newtonsoft.Json.Tests.Serialization public string Query { get; set; } public string Language { get; set; } } + +#if !(WINDOWS_PHONE || SILVERLIGHT) + public class SerializableWrapper + { + public object Content { get; set; } + + public override bool Equals(object obj) + { + SerializableWrapper w = obj as SerializableWrapper; + + if (w == null) + return false; + + return Equals(w.Content, Content); + } + } + + public interface IExample + : ISerializable + { + String Name + { + get; + } + } + + [Serializable] + public class Example + : IExample + { + public Example(String name) + { + this.Name = name; + } + + protected Example(SerializationInfo info, StreamingContext context) + { + this.Name = info.GetString("name"); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("name", this.Name); + } + + public String Name { get; set; } + + public override bool Equals(object obj) + { + if (obj == null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj is IExample) + { + return this.Name.Equals(((IExample)obj).Name); + } + else + { + return false; + } + } + } +#endif } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs index eee63999..c08324c4 100644 --- a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs @@ -53,6 +53,9 @@ namespace Newtonsoft.Json.Converters writer.WriteStartObject(); foreach (DataColumn column in row.Table.Columns) { + if (serializer.NullValueHandling == NullValueHandling.Ignore && (row[column] == null || row[column] == DBNull.Value)) + continue; + writer.WritePropertyName((resolver != null) ? resolver.ResolvePropertyName(column.ColumnName) : column.ColumnName); serializer.Serialize(writer, row[column]); } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index b5514192..a28c55c7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -152,7 +152,7 @@ namespace Newtonsoft.Json.Serialization #if !SILVERLIGHT && !PocketPC else if (valueContract is JsonISerializableContract) { - SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract); + SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract, member, collectionValueContract); } #endif #if !(NET35 || NET20 || WINDOWS_PHONE) @@ -475,13 +475,18 @@ namespace Newtonsoft.Json.Serialization [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1903:UseOnlyApiFromTargetedFramework", MessageId = "System.Security.SecuritySafeCriticalAttribute")] [SecuritySafeCritical] #endif - private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract) + private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContract collectionValueContract) { contract.InvokeOnSerializing(value, Serializer.Context); SerializeStack.Add(value); writer.WriteStartObject(); + if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract)) + { + WriteTypeProperty(writer, contract.UnderlyingType); + } + SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new FormatterConverter()); value.GetObjectData(serializationInfo, Serializer.Context);