-Fixed deserializing Regex when using StringEnumConverter

-Fixed serializing and deserializing typed DataSets
This commit is contained in:
James Newton-King
2013-05-04 15:28:01 +12:00
parent b6816866ba
commit 6f2b931a90
22 changed files with 393 additions and 39 deletions
@@ -30,6 +30,7 @@ using System.Globalization;
using System.Numerics;
#endif
using System.Text;
using System.Text.RegularExpressions;
#if !NETFX_CORE
using NUnit.Framework;
#else
@@ -1469,5 +1470,44 @@ namespace Newtonsoft.Json.Tests.Bson
Assert.AreEqual(i, c.Blah);
}
#endif
public class RegexTestClass
{
public Regex Regex { get; set; }
}
[Test]
public void DeserializeRegexNonConverterBson()
{
string hex = "46-00-00-00-03-52-65-67-65-78-00-3A-00-00-00-02-70-61-74-74-65-72-6E-00-05-00-00-00-28-68-69-29-00-10-6F-70-74-69-6F-6E-73-00-05-00-00-00-12-6D-61-74-63-68-54-69-6D-65-6F-75-74-00-F0-D8-FF-FF-FF-FF-FF-FF-00-00";
byte[] data = HexToBytes(hex);
MemoryStream ms = new MemoryStream(data);
BsonReader reader = new BsonReader(ms);
JsonSerializer serializer = new JsonSerializer();
RegexTestClass c = serializer.Deserialize<RegexTestClass>(reader);
Assert.AreEqual("(hi)", c.Regex.ToString());
Assert.AreEqual(RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase, c.Regex.Options);
}
[Test]
public void DeserializeRegexBson()
{
string hex = "15-00-00-00-0B-52-65-67-65-78-00-28-68-69-29-00-69-75-78-00-00";
byte[] data = HexToBytes(hex);
MemoryStream ms = new MemoryStream(data);
BsonReader reader = new BsonReader(ms);
JsonSerializer serializer = new JsonSerializer();
RegexTestClass c = serializer.Deserialize<RegexTestClass>(reader);
Assert.AreEqual("(hi)", c.Regex.ToString());
Assert.AreEqual(RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase, c.Regex.Options);
}
}
}
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using System.Numerics;
#endif
using System.Text;
using System.Text.RegularExpressions;
#if !NETFX_CORE
using NUnit.Framework;
#else
@@ -38,6 +39,7 @@ using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAtt
#endif
using Newtonsoft.Json.Bson;
using System.IO;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Tests.TestObjects;
using System.Globalization;
@@ -715,6 +717,35 @@ namespace Newtonsoft.Json.Tests.Bson
Assert.AreEqual("10-00-00-00-09-30-00-C8-88-07-6B-DC-00-00-00-00", (BitConverter.ToString(ms.ToArray())));
}
public class RegexTestClass
{
public Regex Regex { get; set; }
}
[Test]
public void SerializeDeserializeRegex()
{
Regex r1 = new Regex("(hi)", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
RegexTestClass c = new RegexTestClass { Regex = r1 };
MemoryStream ms = new MemoryStream();
JsonSerializer serializer = new JsonSerializer();
BsonWriter writer = new BsonWriter(ms);
serializer.Serialize(writer, c);
string hex = BitConverter.ToString(ms.ToArray());
Assert.AreEqual("15-00-00-00-0B-52-65-67-65-78-00-28-68-69-29-00-69-75-78-00-00", hex);
JObject o = (JObject)JObject.ReadFrom(new BsonReader(new MemoryStream(ms.ToArray())));
Console.WriteLine(o.ToString());
//{
// "Regex": "/(hi)/iux"
//}
}
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE || PORTABLE40)
[Test]
public void WriteBigInteger()
@@ -403,6 +403,56 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.AreEqual(c.Table.Rows.Count, c2.Table.Rows.Count);
Assert.AreEqual(c.After, c2.After);
}
[Test]
public void SerializedTypedDataSet()
{
CustomerDataSet ds = new CustomerDataSet();
ds.Customers.AddCustomersRow("234");
string json = JsonConvert.SerializeObject(ds, Formatting.Indented);
Assert.AreEqual(@"{
""Customers"": [
{
""CustomerID"": ""234""
}
]
}", json);
CustomerDataSet ds1 = new CustomerDataSet();
DataTable table = ds1.Tables["Customers"];
DataRow row = ds1.Tables["Customers"].NewRow();
row["CustomerID"] = "234";
table.Rows.Add(row);
string json1 = JsonConvert.SerializeObject(ds1, Formatting.Indented);
Assert.AreEqual(@"{
""Customers"": [
{
""CustomerID"": ""234""
}
]
}", json1);
}
[Test]
public void DeserializedTypedDataSet()
{
string json = @"{
""Customers"": [
{
""CustomerID"": ""234""
}
]
}";
var ds = JsonConvert.DeserializeObject<CustomerDataSet>(json);
Assert.AreEqual("234", ds.Customers[0].CustomerID);
}
}
}
#endif
@@ -25,8 +25,8 @@
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE || PORTABLE40)
using System;
#if !NETFX_CORE
using System.Collections.Generic;
#if !NETFX_CORE
using NUnit.Framework;
#else
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
@@ -36,6 +36,7 @@ using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAtt
#if !NETFX_CORE
using System.Data;
#endif
using Newtonsoft.Json.Tests.TestObjects;
namespace Newtonsoft.Json.Tests.Converters
{
@@ -270,6 +271,36 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.AreEqual(1, pair2.Key.Rows.Count);
Assert.AreEqual("item!", pair2.Key.Rows[0]["item"]);
}
[Test]
public void SerializedTypedDataTable()
{
CustomerDataSet.CustomersDataTable dt = new CustomerDataSet.CustomersDataTable();
dt.AddCustomersRow("432");
string json = JsonConvert.SerializeObject(dt, Formatting.Indented);
Assert.AreEqual(@"[
{
""CustomerID"": ""432""
}
]", json);
}
[Test]
public void DeserializedTypedDataTable()
{
string json = @"[
{
""CustomerID"": ""432""
}
]";
var dt = JsonConvert.DeserializeObject<CustomerDataSet.CustomersDataTable>(json);
Assert.AreEqual("432", dt[0].CustomerID);
}
}
}
#endif
@@ -35,6 +35,7 @@ using System.IO;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
#if !NETFX_CORE
using NUnit.Framework;
@@ -68,6 +69,57 @@ namespace Newtonsoft.Json.Tests.Converters
}", json);
}
[Test]
public void SerializeCamelCaseAndStringEnums()
{
Regex regex = new Regex("abc", RegexOptions.IgnoreCase);
string json = JsonConvert.SerializeObject(regex, Formatting.Indented, new JsonSerializerSettings
{
Converters = {new RegexConverter(),new StringEnumConverter() { CamelCaseText = true }},
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
Assert.AreEqual(@"{
""pattern"": ""abc"",
""options"": ""ignoreCase""
}", json);
}
[Test]
public void DeserializeCamelCaseAndStringEnums()
{
string json = @"{
""pattern"": ""abc"",
""options"": ""ignoreCase""
}";
Regex regex = JsonConvert.DeserializeObject<Regex>(json, new JsonSerializerSettings
{
Converters = { new RegexConverter() }
});
Assert.AreEqual("abc", regex.ToString());
Assert.AreEqual(RegexOptions.IgnoreCase, regex.Options);
}
[Test]
public void DeserializeISerializeRegexJson()
{
string json = @"{
""Regex"": {
""pattern"": ""(hi)"",
""options"": 5,
""matchTimeout"": -10000
}
}";
RegexTestClass r = JsonConvert.DeserializeObject<RegexTestClass>(json);
Assert.AreEqual("(hi)", r.Regex.ToString());
Assert.AreEqual(RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture, r.Regex.Options);
}
[Test]
public void SerializeToBson()
{
@@ -26,6 +26,7 @@
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Converters;
#if !NETFX_CORE
using NUnit.Framework;
@@ -336,6 +337,7 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.IsNull(c.NullableStoreColor2);
}
[Test]
public void DeserializeInvalidString()
{
string json = "{ \"Value\" : \"Three\" }";
@@ -109,6 +109,9 @@
<Compile Include="TestObjects\Content.cs" />
<Compile Include="TestObjects\ContentBaseClass.cs" />
<Compile Include="TestObjects\ContentSubClass.cs" />
<Compile Include="TestObjects\CustomerDataSet.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TestObjects\DictionaryInterfaceClass.cs" />
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
<Compile Include="TestObjects\Event.cs" />
@@ -150,6 +150,7 @@
<Compile Include="TestObjects\Container.cs" />
<Compile Include="TestObjects\ContentBaseClass.cs" />
<Compile Include="TestObjects\ContentSubClass.cs" />
<Compile Include="TestObjects\CustomerDataSet.cs" />
<Compile Include="TestObjects\Foo.cs" />
<Compile Include="TestObjects\HolderClass.cs" />
<Compile Include="TestObjects\IPrivateImplementationA.cs" />
@@ -268,6 +268,9 @@
<Compile Include="TestObjects\Container.cs" />
<Compile Include="TestObjects\ContentBaseClass.cs" />
<Compile Include="TestObjects\ContentSubClass.cs" />
<Compile Include="TestObjects\CustomerDataSet.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TestObjects\Foo.cs" />
<Compile Include="TestObjects\HolderClass.cs" />
<Compile Include="TestObjects\IPrivateImplementationA.cs" />
@@ -149,6 +149,9 @@
<Compile Include="TestObjects\Container.cs" />
<Compile Include="TestObjects\ContentBaseClass.cs" />
<Compile Include="TestObjects\ContentSubClass.cs" />
<Compile Include="TestObjects\CustomerDataSet.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TestObjects\Foo.cs" />
<Compile Include="TestObjects\HolderClass.cs" />
<Compile Include="TestObjects\IPrivateImplementationA.cs" />
@@ -263,6 +263,9 @@
<Compile Include="TestObjects\ConverableMembers.cs" />
<Compile Include="TestObjects\ConverterPrecedenceClass.cs" />
<Compile Include="TestObjects\ConverterPrecedenceClassConverter.cs" />
<Compile Include="TestObjects\CustomerDataSet.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TestObjects\DateTimeErrorObjectCollection.cs" />
<Compile Include="TestObjects\DateTimeTestClass.cs" />
<Compile Include="TestObjects\DefaultValueAttributeTestClass.cs" />
@@ -75,4 +75,4 @@ using System.Security;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
[assembly: AssemblyFileVersion("5.0.4.16102")]
[assembly: AssemblyFileVersion("5.0.4.16104")]
@@ -258,5 +258,88 @@ namespace Newtonsoft.Json.Tests.Serialization
}", includeCompilerGeneratedJson);
}
#endif
//public class NullAsStringValueProvider : IValueProvider
//{
// private readonly ReflectionValueProvider _internalProvider;
// public NullAsStringValueProvider(MemberInfo memberInfo)
// {
// _internalProvider = new ReflectionValueProvider(memberInfo);
// }
// public void SetValue(object target, object value)
// {
// _internalProvider.SetValue(target, value);
// }
// public object GetValue(object target)
// {
// object value = _internalProvider.GetValue(target);
// if (value == null)
// return string.Empty;
// return value;
// }
//}
//public class NullAsStringContractResolver : DefaultContractResolver
//{
// protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
// {
// JsonProperty property = base.CreateProperty(member, memberSerialization);
// //property.ValueProvider = new NullAsStringValueProvider(member);
// //property..Converter = new NullAsStringJsonConverter();
// return property;
// }
// protected override JsonPrimitiveContract CreatePrimitiveContract(Type objectType)
// {
// return base.CreatePrimitiveContract(objectType);
// }
//}
//public class NullAsStringTestClass
//{
// public int? Integer { get; set; }
// public DateTime? DateTime { get; set; }
//}
//public class NullAsStringJsonConverter : JsonConverter
//{
// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
// {
// if (value == null)
// writer.WriteValue(string.Empty);
// }
// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
// {
// throw new NotImplementedException();
// }
// public override bool CanRead
// {
// get { return false; }
// }
// public override bool CanConvert(Type objectType)
// {
// return ReflectionUtils.IsNullableType(objectType);
// }
//}
//[Test]
//public void sdfsdf()
//{
// string json = JsonConvert.SerializeObject(
// new NullAsStringTestClass(),
// new JsonSerializerSettings { ContractResolver = new NullAsStringContractResolver()});
// Console.WriteLine(json);
//}
}
}
@@ -40,6 +40,7 @@ using System.Threading;
using System.Web.Script.Serialization;
#endif
using System.Text;
using System.Text.RegularExpressions;
#if !NETFX_CORE
using NUnit.Framework;
#else
@@ -158,6 +159,19 @@ namespace Newtonsoft.Json.Tests.Serialization
}
}
[Test]
public void SerializeDeserializeRegex()
{
Regex regex = new Regex("(hi)", RegexOptions.CultureInvariant);
string json = JsonConvert.SerializeObject(regex, Formatting.Indented);
Regex r2 = JsonConvert.DeserializeObject<Regex>(json);
Assert.AreEqual("(hi)", r2.ToString());
Assert.AreEqual(RegexOptions.CultureInvariant, r2.Options);
}
[Test]
public void ExtensionDataTest()
{
@@ -29,7 +29,6 @@ using System.Globalization;
using System.IO;
#if NET20
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Runtime.Serialization.Json;
#endif
@@ -70,7 +70,10 @@ namespace Newtonsoft.Json.Converters
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
DataSet ds = new DataSet();
// handle typed datasets
DataSet ds = (objectType == typeof(DataSet))
? new DataSet()
: (DataSet)Activator.CreateInstance(objectType);
DataTableConverter converter = new DataTableConverter();
@@ -78,8 +81,13 @@ namespace Newtonsoft.Json.Converters
while (reader.TokenType == JsonToken.PropertyName)
{
DataTable dt = (DataTable)converter.ReadJson(reader, typeof (DataTable), null, serializer);
ds.Tables.Add(dt);
DataTable dt = ds.Tables[(string)reader.Value];
bool exists = (dt != null);
dt = (DataTable)converter.ReadJson(reader, typeof (DataTable), dt, serializer);
if (!exists)
ds.Tables.Add(dt);
reader.Read();
}
@@ -96,7 +104,7 @@ namespace Newtonsoft.Json.Converters
/// </returns>
public override bool CanConvert(Type valueType)
{
return (valueType == typeof(DataSet));
return typeof(DataSet).IsAssignableFrom(valueType);
}
}
}
@@ -75,17 +75,22 @@ namespace Newtonsoft.Json.Converters
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
DataTable dt;
DataTable dt = existingValue as DataTable;
if (dt == null)
{
// handle typed datasets
dt = (objectType == typeof(DataTable))
? new DataTable()
: (DataTable)Activator.CreateInstance(objectType);
}
if (reader.TokenType == JsonToken.PropertyName)
{
dt = new DataTable((string)reader.Value);
dt.TableName = (string)reader.Value;
reader.Read();
}
else
{
dt = new DataTable();
}
reader.Read();
@@ -149,7 +154,7 @@ namespace Newtonsoft.Json.Converters
/// </returns>
public override bool CanConvert(Type valueType)
{
return (valueType == typeof(DataTable));
return typeof(DataTable).IsAssignableFrom(valueType);
}
}
}
@@ -27,6 +27,7 @@ using System;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Bson;
using System.Globalization;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Converters
{
@@ -35,6 +36,9 @@ namespace Newtonsoft.Json.Converters
/// </summary>
public class RegexConverter : JsonConverter
{
private const string PatternName = "Pattern";
private const string OptionsName = "Options";
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
@@ -49,7 +53,7 @@ namespace Newtonsoft.Json.Converters
if (bsonWriter != null)
WriteBson(bsonWriter, regex);
else
WriteJson(writer, regex);
WriteJson(writer, regex, serializer);
}
private bool HasFlag(RegexOptions options, RegexOptions flag)
@@ -85,13 +89,15 @@ namespace Newtonsoft.Json.Converters
writer.WriteRegex(regex.ToString(), options);
}
private void WriteJson(JsonWriter writer, Regex regex)
private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer)
{
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
writer.WriteStartObject();
writer.WritePropertyName("Pattern");
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName);
writer.WriteValue(regex.ToString());
writer.WritePropertyName("Options");
writer.WriteValue((int)regex.Options);
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(OptionsName) : OptionsName);
serializer.Serialize(writer, regex.Options);
writer.WriteEndObject();
}
@@ -105,15 +111,16 @@ namespace Newtonsoft.Json.Converters
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
BsonReader bsonReader = reader as BsonReader;
if (reader.TokenType == JsonToken.StartObject)
return ReadRegexObject(reader, serializer);
if (reader.TokenType == JsonToken.String)
return ReadRegexString(reader);
if (bsonReader != null)
return ReadBson(bsonReader);
else
return ReadJson(reader);
throw JsonSerializationException.Create(reader, "Unexpected token when reading Regex.");
}
private object ReadBson(BsonReader reader)
private object ReadRegexString(JsonReader reader)
{
string regexText = (string)reader.Value;
int patternOptionDelimiterIndex = regexText.LastIndexOf('/');
@@ -144,19 +151,39 @@ namespace Newtonsoft.Json.Converters
return new Regex(patternText, options);
}
private Regex ReadJson(JsonReader reader)
private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer)
{
reader.Read();
reader.Read();
string pattern = (string)reader.Value;
string pattern = null;
RegexOptions? options = null;
reader.Read();
reader.Read();
int options = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
string propertyName = reader.Value.ToString();
reader.Read();
if (!reader.Read())
throw JsonSerializationException.Create(reader, "Unexpected end when reading Regex.");
return new Regex(pattern, (RegexOptions) options);
if (string.Equals(propertyName, PatternName, StringComparison.OrdinalIgnoreCase))
pattern = (string)reader.Value;
else if (string.Equals(propertyName, OptionsName, StringComparison.OrdinalIgnoreCase))
options = serializer.Deserialize<RegexOptions>(reader);
else
reader.Skip();
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
if (pattern == null)
throw JsonSerializationException.Create(reader, "Error deserializing Regex. No pattern found.");
return new Regex(pattern, options ?? RegexOptions.None);
}
}
throw JsonSerializationException.Create(reader, "Unexpected end when reading Regex.");
}
/// <summary>
+1
View File
@@ -514,6 +514,7 @@ namespace Newtonsoft.Json
if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
{
// insert settings converters at the beginning so they take precedence
// if user wants to remove one of the default converters they will have to do it manually
for (int i = 0; i < settings.Converters.Count; i++)
{
serializer.Converters.Insert(i, settings.Converters[i]);
@@ -92,6 +92,6 @@ using System.Security;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
[assembly: AssemblyFileVersion("5.0.4.16102")]
[assembly: AssemblyFileVersion("5.0.4.16104")]
[assembly: CLSCompliant(true)]
@@ -112,7 +112,8 @@ namespace Newtonsoft.Json.Serialization
new JsonValueConverter(),
#endif
new KeyValuePairConverter(),
new BsonObjectIdConverter()
new BsonObjectIdConverter(),
new RegexConverter()
};
private static Dictionary<ResolverContractKey, JsonContract> _sharedContractCache;
@@ -24,9 +24,6 @@
#endregion
using System;
#if !(PORTABLE || PORTABLE40 || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
using System.Numerics;
#endif
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Serialization