-Added DataSetConverter, DataTableConverter

-Added JPath and SelectToken to JToken
-Fixed schema id not being written for collections
-Fixed TimeSpan serialization on Compact Framework
-Fixed unicode line break string encoding
This commit is contained in:
JamesNK
2009-10-14 02:40:20 +00:00
parent b313445e01
commit b4b3905714
23 changed files with 1053 additions and 10 deletions
@@ -0,0 +1,199 @@
#if !SILVERLIGHT
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Converters;
using NUnit.Framework;
using Newtonsoft.Json.Tests.TestObjects;
using System.Data;
namespace Newtonsoft.Json.Tests.Converters
{
public class DataSetConverterTests : TestFixtureBase
{
[Test]
public void SerializeAndDeserialize()
{
DataSet dataSet = new DataSet("dataSet");
dataSet.Namespace = "NetFrameWork";
DataTable table = new DataTable();
DataColumn idColumn = new DataColumn("id", typeof(int));
idColumn.AutoIncrement = true;
DataColumn itemColumn = new DataColumn("item");
table.Columns.Add(idColumn);
table.Columns.Add(itemColumn);
dataSet.Tables.Add(table);
for (int i = 0; i < 2; i++)
{
DataRow newRow = table.NewRow();
newRow["item"] = "item " + i;
table.Rows.Add(newRow);
}
dataSet.AcceptChanges();
string json = JsonConvert.SerializeObject(dataSet, Formatting.Indented);
Assert.AreEqual(@"{
""Table1"": [
{
""id"": 0,
""item"": ""item 0""
},
{
""id"": 1,
""item"": ""item 1""
}
]
}", json);
DataSet deserializedDataSet = JsonConvert.DeserializeObject<DataSet>(json);
Assert.IsNotNull(deserializedDataSet);
Assert.AreEqual(1, deserializedDataSet.Tables.Count);
DataTable dt = deserializedDataSet.Tables[0];
Assert.AreEqual("Table1", dt.TableName);
Assert.AreEqual(2, dt.Columns.Count);
Assert.AreEqual("id", dt.Columns[0].ColumnName);
Assert.AreEqual(typeof(long), dt.Columns[0].DataType);
Assert.AreEqual("item", dt.Columns[1].ColumnName);
Assert.AreEqual(typeof(string), dt.Columns[1].DataType);
Assert.AreEqual(2, dt.Rows.Count);
}
public void SerializeMultiTableDataSet()
{
DataSet ds = new DataSet();
ds.Tables.Add(CreateDataTable("FirstTable"));
ds.Tables.Add(CreateDataTable("SecondTable"));
string json = JsonConvert.SerializeObject(ds, Formatting.Indented, new IsoDateTimeConverter());
Assert.AreEqual(@"{
""FirstTable"": [
{
""StringCol"": ""Item Name"",
""Int32Col"": 2147483647,
""BooleanCol"": true,
""TimeSpanCol"": ""10.22:10:15.1000000"",
""DateTimeCol"": ""2000-12-29T00:00:00"",
""DecimalCol"": 64.0021
}
],
""SecondTable"": [
{
""StringCol"": ""Item Name"",
""Int32Col"": 2147483647,
""BooleanCol"": true,
""TimeSpanCol"": ""10.22:10:15.1000000"",
""DateTimeCol"": ""2000-12-29T00:00:00"",
""DecimalCol"": 64.0021
}
]
}", json);
}
[Test]
public void DeserializeMultiTableDataSet()
{
string json = @"{
""FirstTable"": [
{
""StringCol"": ""Item Name"",
""Int32Col"": 2147483647,
""BooleanCol"": true,
""TimeSpanCol"": ""10.22:10:15.1000000"",
""DateTimeCol"": ""2000-12-29T00:00:00"",
""DecimalCol"": 64.0021
}
],
""SecondTable"": [
{
""StringCol"": ""Item Name"",
""Int32Col"": 2147483647,
""BooleanCol"": true,
""TimeSpanCol"": ""10.22:10:15.1000000"",
""DateTimeCol"": ""2000-12-29T00:00:00"",
""DecimalCol"": 64.0021
}
]
}";
DataSet ds = JsonConvert.DeserializeObject<DataSet>(json, new IsoDateTimeConverter());
Assert.IsNotNull(ds);
Assert.AreEqual(2, ds.Tables.Count);
Assert.AreEqual("FirstTable", ds.Tables[0].TableName);
Assert.AreEqual("SecondTable", ds.Tables[1].TableName);
DataTable dt = ds.Tables[0];
Assert.AreEqual("StringCol", dt.Columns[0].ColumnName);
Assert.AreEqual(typeof(string), dt.Columns[0].DataType);
Assert.AreEqual("Int32Col", dt.Columns[1].ColumnName);
Assert.AreEqual(typeof(long), dt.Columns[1].DataType);
Assert.AreEqual("BooleanCol", dt.Columns[2].ColumnName);
Assert.AreEqual(typeof(bool), dt.Columns[2].DataType);
Assert.AreEqual("TimeSpanCol", dt.Columns[3].ColumnName);
Assert.AreEqual(typeof(string), dt.Columns[3].DataType);
Assert.AreEqual("DateTimeCol", dt.Columns[4].ColumnName);
Assert.AreEqual(typeof(string), dt.Columns[4].DataType);
Assert.AreEqual("DecimalCol", dt.Columns[5].ColumnName);
Assert.AreEqual(typeof(double), dt.Columns[5].DataType);
Assert.AreEqual(1, ds.Tables[0].Rows.Count);
Assert.AreEqual(1, ds.Tables[1].Rows.Count);
}
private DataTable CreateDataTable(string dataTableName)
{
// create a new DataTable.
DataTable myTable = new DataTable(dataTableName);
// create DataColumn objects of data types.
DataColumn colString = new DataColumn("StringCol");
colString.DataType = typeof(string);
myTable.Columns.Add(colString);
DataColumn colInt32 = new DataColumn("Int32Col");
colInt32.DataType = typeof(int);
myTable.Columns.Add(colInt32);
DataColumn colBoolean = new DataColumn("BooleanCol");
colBoolean.DataType = typeof(bool);
myTable.Columns.Add(colBoolean);
DataColumn colTimeSpan = new DataColumn("TimeSpanCol");
colTimeSpan.DataType = typeof(TimeSpan);
myTable.Columns.Add(colTimeSpan);
DataColumn colDateTime = new DataColumn("DateTimeCol");
colDateTime.DataType = typeof(DateTime);
colDateTime.DateTimeMode = DataSetDateTime.Utc;
myTable.Columns.Add(colDateTime);
DataColumn colDecimal = new DataColumn("DecimalCol");
colDecimal.DataType = typeof(decimal);
myTable.Columns.Add(colDecimal);
// populate one row with values.
DataRow myNewRow = myTable.NewRow();
myNewRow["StringCol"] = "Item Name";
myNewRow["Int32Col"] = 2147483647;
myNewRow["BooleanCol"] = true;
myNewRow["TimeSpanCol"] = new TimeSpan(10, 22, 10, 15, 100);
myNewRow["DateTimeCol"] = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc);
myNewRow["DecimalCol"] = 64.0021;
myTable.Rows.Add(myNewRow);
return myTable;
}
}
}
#endif
@@ -0,0 +1,107 @@
#if !SILVERLIGHT
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Converters;
using NUnit.Framework;
using Newtonsoft.Json.Tests.TestObjects;
using System.Data;
namespace Newtonsoft.Json.Tests.Converters
{
public class DataTableConverterTests : TestFixtureBase
{
[Test]
public void Deserialize()
{
string json = @"[
{
""id"": 0,
""item"": ""item 0""
},
{
""id"": 1,
""item"": ""item 1""
}
]";
DataTable deserializedDataTable = JsonConvert.DeserializeObject<DataTable>(json);
Assert.IsNotNull(deserializedDataTable);
Assert.AreEqual(string.Empty, deserializedDataTable.TableName);
Assert.AreEqual(2, deserializedDataTable.Columns.Count);
Assert.AreEqual("id", deserializedDataTable.Columns[0].ColumnName);
Assert.AreEqual(typeof(long), deserializedDataTable.Columns[0].DataType);
Assert.AreEqual("item", deserializedDataTable.Columns[1].ColumnName);
Assert.AreEqual(typeof(string), deserializedDataTable.Columns[1].DataType);
Assert.AreEqual(2, deserializedDataTable.Rows.Count);
DataRow dr1 = deserializedDataTable.Rows[0];
Assert.AreEqual(0, dr1["id"]);
Assert.AreEqual("item 0", dr1["item"]);
DataRow dr2 = deserializedDataTable.Rows[1];
Assert.AreEqual(1, dr2["id"]);
Assert.AreEqual("item 1", dr2["item"]);
}
[Test]
public void Serialize()
{
// create a new DataTable.
DataTable myTable = new DataTable("blah");
// create DataColumn objects of data types.
DataColumn colString = new DataColumn("StringCol");
colString.DataType = typeof(string);
myTable.Columns.Add(colString);
DataColumn colInt32 = new DataColumn("Int32Col");
colInt32.DataType = typeof(int);
myTable.Columns.Add(colInt32);
DataColumn colBoolean = new DataColumn("BooleanCol");
colBoolean.DataType = typeof(bool);
myTable.Columns.Add(colBoolean);
DataColumn colTimeSpan = new DataColumn("TimeSpanCol");
colTimeSpan.DataType = typeof(TimeSpan);
myTable.Columns.Add(colTimeSpan);
DataColumn colDateTime = new DataColumn("DateTimeCol");
colDateTime.DataType = typeof(DateTime);
colDateTime.DateTimeMode = DataSetDateTime.Utc;
myTable.Columns.Add(colDateTime);
DataColumn colDecimal = new DataColumn("DecimalCol");
colDecimal.DataType = typeof(decimal);
myTable.Columns.Add(colDecimal);
// populate one row with values.
DataRow myNewRow = myTable.NewRow();
myNewRow["StringCol"] = "Item Name";
myNewRow["Int32Col"] = 2147483647;
myNewRow["BooleanCol"] = true;
myNewRow["TimeSpanCol"] = new TimeSpan(10, 22, 10, 15, 100);
myNewRow["DateTimeCol"] = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc);
myNewRow["DecimalCol"] = 64.0021;
myTable.Rows.Add(myNewRow);
string json = JsonConvert.SerializeObject(myTable, Formatting.Indented);
Assert.AreEqual(@"[
{
""StringCol"": ""Item Name"",
""Int32Col"": 2147483647,
""BooleanCol"": true,
""TimeSpanCol"": ""10.22:10:15.1000000"",
""DateTimeCol"": ""\/Date(978048000000)\/"",
""DecimalCol"": 64.0021
}
]", json);
}
}
}
#endif
@@ -154,6 +154,21 @@ now brown cow?", '"', true);
Assert.AreEqual(result, @"'Fred\'s ""cat"".'");
}
[Test]
public void EscapeJavaScriptString_UnicodeLinefeeds()
{
string result;
result = JavaScriptUtils.ToEscapedJavaScriptString("before" + '\u0085' + "after", '"', true);
Assert.AreEqual(@"""before\u0085after""", result);
result = JavaScriptUtils.ToEscapedJavaScriptString("before" + '\u2028' + "after", '"', true);
Assert.AreEqual(@"""before\u2028after""", result);
result = JavaScriptUtils.ToEscapedJavaScriptString("before" + '\u2029' + "after", '"', true);
Assert.AreEqual(@"""before\u2029after""", result);
}
[Test]
[ExpectedException(typeof(ArgumentException), ExpectedMessage = "Unsupported type: System.Version. Use the JsonSerializer class to get the object's JSON representation.")]
public void ToStringInvalid()
@@ -0,0 +1,246 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Tests.TestObjects;
using NUnit.Framework;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using System.IO;
using System.Collections;
namespace Newtonsoft.Json.Tests.Linq
{
public class JPathTests : TestFixtureBase
{
[Test]
public void SingleProperty()
{
JPath path = new JPath("Blah");
Assert.AreEqual(1, path.Parts.Count);
Assert.AreEqual("Blah", path.Parts[0]);
}
[Test]
public void TwoProperties()
{
JPath path = new JPath("Blah.Two");
Assert.AreEqual(2, path.Parts.Count);
Assert.AreEqual("Blah", path.Parts[0]);
Assert.AreEqual("Two", path.Parts[1]);
}
[Test]
public void SinglePropertyAndIndexer()
{
JPath path = new JPath("Blah[0]");
Assert.AreEqual(2, path.Parts.Count);
Assert.AreEqual("Blah", path.Parts[0]);
Assert.AreEqual(0, path.Parts[1]);
}
[Test]
public void MultiplePropertiesAndIndexers()
{
JPath path = new JPath("Blah[0].Two.Three[1].Four");
Assert.AreEqual(6, path.Parts.Count);
Assert.AreEqual("Blah", path.Parts[0]);
Assert.AreEqual(0, path.Parts[1]);
Assert.AreEqual("Two", path.Parts[2]);
Assert.AreEqual("Three", path.Parts[3]);
Assert.AreEqual(1, path.Parts[4]);
Assert.AreEqual("Four", path.Parts[5]);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = @"Unexpected character while parsing path indexer: [")]
public void BadCharactersInIndexer()
{
new JPath("Blah[[0]].Two.Three[1].Four");
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = @"Path ended with open indexer. Expected ]")]
public void UnclosedIndexer()
{
new JPath("Blah[0");
}
[Test]
public void AdditionalDots()
{
JPath path = new JPath(".Blah..[0]..Two.Three....[1].Four.");
Assert.AreEqual(6, path.Parts.Count);
Assert.AreEqual("Blah", path.Parts[0]);
Assert.AreEqual(0, path.Parts[1]);
Assert.AreEqual("Two", path.Parts[2]);
Assert.AreEqual("Three", path.Parts[3]);
Assert.AreEqual(1, path.Parts[4]);
Assert.AreEqual("Four", path.Parts[5]);
}
[Test]
public void IndexerOnly()
{
JPath path = new JPath("[111119990]");
Assert.AreEqual(1, path.Parts.Count);
Assert.AreEqual(111119990, path.Parts[0]);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = "Empty path indexer.")]
public void EmptyIndexer()
{
new JPath("[]");
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = "Unexpected character while parsing path: ]")]
public void IndexerCloseInProperty()
{
new JPath("]");
}
[Test]
public void AdjacentIndexers()
{
JPath path = new JPath("[1][0][0][" + int.MaxValue + "]");
Assert.AreEqual(4, path.Parts.Count);
Assert.AreEqual(1, path.Parts[0]);
Assert.AreEqual(0, path.Parts[1]);
Assert.AreEqual(0, path.Parts[2]);
Assert.AreEqual(int.MaxValue, path.Parts[3]);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = "Unexpected character following indexer: B")]
public void MissingDotAfterIndexer()
{
new JPath("[1]Blah");
}
[Test]
public void EvaluateSingleProperty()
{
JObject o = new JObject(
new JProperty("Blah", 1));
JToken t = o.SelectToken("Blah");
Assert.IsNotNull(t);
Assert.AreEqual(JTokenType.Integer, t.Type);
Assert.AreEqual(1, (int)t);
}
[Test]
public void EvaluateMissingProperty()
{
JObject o = new JObject(
new JProperty("Blah", 1));
JToken t = o.SelectToken("Missing[1]");
Assert.IsNull(t);
}
[Test]
public void EvaluateIndexerOnObject()
{
JObject o = new JObject(
new JProperty("Blah", 1));
JToken t = o.SelectToken("[1]");
Assert.IsNull(t);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = @"Index 1 not valid on JObject.")]
public void EvaluateIndexerOnObjectWithError()
{
JObject o = new JObject(
new JProperty("Blah", 1));
o.SelectToken("[1]", true);
}
[Test]
public void EvaluatePropertyOnArray()
{
JArray a = new JArray(1, 2, 3, 4, 5);
JToken t = a.SelectToken("BlahBlah");
Assert.IsNull(t);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = @"Property 'BlahBlah' not valid on JArray.")]
public void EvaluatePropertyOnArrayWithError()
{
JArray a = new JArray(1, 2, 3, 4, 5);
a.SelectToken("BlahBlah", true);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = @"Index 1 not valid on JConstructor.")]
public void EvaluateIndexerOnConstructorWithError()
{
JConstructor c = new JConstructor("Blah");
c.SelectToken("[1]", true);
}
[Test]
[ExpectedException(typeof(Exception), ExpectedMessage = "Property 'Missing' does not exist on JObject.")]
public void EvaluateMissingPropertyWithError()
{
JObject o = new JObject(
new JProperty("Blah", 1));
o.SelectToken("Missing", true);
}
[Test]
public void EvaluateOutOfBoundsIndxer()
{
JArray a = new JArray(1, 2, 3, 4, 5);
JToken t = a.SelectToken("[1000].Ha");
Assert.IsNull(t);
}
[Test]
[ExpectedException(typeof(IndexOutOfRangeException), ExpectedMessage = "Index 1000 outside the bounds of JArray.")]
public void EvaluateOutOfBoundsIndxerWithError()
{
JArray a = new JArray(1, 2, 3, 4, 5);
a.SelectToken("[1000].Ha", true);
}
[Test]
public void EvaluateArray()
{
JArray a = new JArray(1, 2, 3, 4);
JToken t = a.SelectToken("[1]");
Assert.IsNotNull(t);
Assert.AreEqual(JTokenType.Integer, t.Type);
Assert.AreEqual(2, (int)t);
}
[Test]
public void EvaluateSinglePropertyReturningArray()
{
JObject o = new JObject(
new JProperty("Blah", new [] { 1, 2, 3 }));
JToken t = o.SelectToken("Blah");
Assert.IsNotNull(t);
Assert.AreEqual(JTokenType.Array, t.Type);
t = o.SelectToken("Blah[2]");
Assert.AreEqual(JTokenType.Integer, t.Type);
Assert.AreEqual(3, (int)t);
}
}
}
@@ -60,11 +60,14 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="Linq\ComponentModel\BindingTests.cs" />
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProviderTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
<Compile Include="Linq\JPathTests.cs" />
<Compile Include="Linq\JTokenReaderTest.cs" />
<Compile Include="Linq\JTokenWriterTest.cs" />
<Compile Include="JsonValidatingReaderTests.cs" />
@@ -64,6 +64,8 @@
<ItemGroup>
<Compile Include="Converters\BinaryConverterTests.cs" />
<Compile Include="Converters\CustomCreationConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="JsonArrayAttributeTests.cs" />
<Compile Include="ExceptionTests.cs" />
@@ -72,6 +74,7 @@
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProviderTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
<Compile Include="Linq\JPathTests.cs" />
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
<Compile Include="TestObjects\Content.cs" />
<Compile Include="TestObjects\DictionaryInterfaceClass.cs" />
@@ -64,6 +64,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="ExceptionTests.cs" />
<Compile Include="JsonArrayAttributeTests.cs" />
@@ -71,6 +73,7 @@
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProviderTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
<Compile Include="Linq\JPathTests.cs" />
<Compile Include="Linq\JTokenReaderTest.cs" />
<Compile Include="Linq\JTokenWriterTest.cs" />
<Compile Include="JsonValidatingReaderTests.cs" />
@@ -84,6 +84,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverterTests.cs" />
<Compile Include="Converters\DataTableConverterTests.cs" />
<Compile Include="Converters\DataSetConverterTests.cs" />
<Compile Include="Converters\CustomCreationConverterTests.cs" />
<Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="FileSystemEntityModel.Designer.cs">
@@ -109,6 +111,7 @@
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProviderTests.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
<Compile Include="Linq\JPathTests.cs" />
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
<Compile Include="TestObjects\PersonError.cs" />
<Compile Include="TestObjects\PrivateConstructorTestClass.cs" />
@@ -498,5 +498,82 @@ namespace Newtonsoft.Json.Tests.Schema
}
}", json);
}
[Test]
public void CircularCollectionReferences()
{
Type type = typeof (Workspace);
JsonSchemaGenerator jsonSchemaGenerator = new JsonSchemaGenerator();
jsonSchemaGenerator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
JsonSchema jsonSchema = jsonSchemaGenerator.Generate(type);
// should succeed
Assert.IsNotNull(jsonSchema);
}
}
public class DMDSLBase
{
public String Comment;
}
public class Workspace : DMDSLBase
{
public ControlFlowItemCollection Jobs = new ControlFlowItemCollection();
}
public class ControlFlowItemBase : DMDSLBase
{
public String Name;
}
public class ControlFlowItem : ControlFlowItemBase//A Job
{
public TaskCollection Tasks = new TaskCollection();
public ContainerCollection Containers = new ContainerCollection();
}
public class ControlFlowItemCollection : List<ControlFlowItem>
{
}
public class Task : ControlFlowItemBase
{
public DataFlowTaskCollection DataFlowTasks = new DataFlowTaskCollection();
public BulkInsertTaskCollection BulkInsertTask = new BulkInsertTaskCollection();
}
public class TaskCollection : List<Task>
{
}
public class Container : ControlFlowItemBase
{
public ControlFlowItemCollection ContainerJobs = new ControlFlowItemCollection();
}
public class ContainerCollection : List<Container>
{
}
public class DataFlowTask_DSL : ControlFlowItemBase
{
}
public class DataFlowTaskCollection : List<DataFlowTask_DSL>
{
}
public class SequenceContainer_DSL : Container
{
}
public class BulkInsertTaskCollection : List<BulkInsertTask_DSL>
{
}
public class BulkInsertTask_DSL
{
}
}
@@ -659,6 +659,25 @@ keyword such as type of business.""
Assert.AreEqual(StringComparison.CurrentCultureIgnoreCase, s);
}
public class ClassWithTimeSpan
{
public TimeSpan TimeSpanField;
}
[Test]
public void TimeSpanTest()
{
TimeSpan ts = new TimeSpan(200, 23, 59, 1);
string json = JsonConvert.SerializeObject(new ClassWithTimeSpan { TimeSpanField = ts }, Formatting.Indented);
Assert.AreEqual(@"{
""TimeSpanField"": ""200.23:59:01""
}", json);
ClassWithTimeSpan c = JsonConvert.DeserializeObject<ClassWithTimeSpan>(json);
Assert.AreEqual(ts, c.TimeSpanField);
}
[Test]
public void JsonIgnoreAttributeOnClassTest()
{
@@ -0,0 +1,55 @@
#if !SILVERLIGHT
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace Newtonsoft.Json.Converters
{
public class DataSetConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DataSet dataSet = (DataSet)value;
DataTableConverter converter = new DataTableConverter();
writer.WriteStartObject();
foreach (DataTable table in dataSet.Tables)
{
writer.WritePropertyName(table.TableName);
converter.WriteJson(writer, table, serializer);
}
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
DataSet ds = new DataSet();
DataTableConverter converter = new DataTableConverter();
reader.Read();
while (reader.TokenType == JsonToken.PropertyName)
{
DataTable dt = (DataTable)converter.ReadJson(reader, typeof (DataTable), serializer);
ds.Tables.Add(dt);
}
reader.Read();
return ds;
}
public override bool CanConvert(Type valueType)
{
return typeof(DataSet).IsAssignableFrom(valueType);
}
}
}
#endif
@@ -0,0 +1,107 @@
#if !SILVERLIGHT
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace Newtonsoft.Json.Converters
{
public class DataTableConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DataTable table = (DataTable)value;
writer.WriteStartArray();
foreach (DataRow row in table.Rows)
{
writer.WriteStartObject();
foreach (DataColumn column in row.Table.Columns)
{
writer.WritePropertyName(column.ColumnName);
serializer.Serialize(writer, row[column]);
}
writer.WriteEndObject();
}
writer.WriteEndArray();
}
public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
DataTable dt;
if (reader.TokenType == JsonToken.PropertyName)
{
dt = new DataTable((string)reader.Value);
reader.Read();
}
else
{
dt = new DataTable();
}
reader.Read();
while (reader.TokenType == JsonToken.StartObject)
{
DataRow dr = dt.NewRow();
reader.Read();
while (reader.TokenType == JsonToken.PropertyName)
{
string columnName = (string) reader.Value;
reader.Read();
if (!dt.Columns.Contains(columnName))
{
Type columnType = GetColumnDataType(reader.TokenType);
dt.Columns.Add(new DataColumn(columnName, columnType));
}
dr[columnName] = reader.Value;
reader.Read();
}
dr.EndEdit();
dt.Rows.Add(dr);
reader.Read();
}
reader.Read();
return dt;
}
private static Type GetColumnDataType(JsonToken tokenType)
{
switch (tokenType)
{
case JsonToken.Integer:
return typeof (long);
case JsonToken.Float:
return typeof (double);
case JsonToken.String:
case JsonToken.Null:
case JsonToken.Undefined:
return typeof (string);
case JsonToken.Boolean:
return typeof (bool);
case JsonToken.Date:
return typeof (DateTime);
default:
throw new ArgumentOutOfRangeException();
}
}
public override bool CanConvert(Type valueType)
{
return typeof(DataTable).IsAssignableFrom(valueType);
}
}
}
#endif
+6 -1
View File
@@ -57,7 +57,12 @@ namespace Newtonsoft.Json
private static readonly IList<JsonConverter> BuiltInConverters = new List<JsonConverter>
{
#if !PocketPC && !SILVERLIGHT && !NET20
new EntityKeyMemberConverter()
new EntityKeyMemberConverter(),
#endif
new BinaryConverter(),
#if !SILVERLIGHT
new DataSetConverter(),
new DataTableConverter()
#endif
};
+170
View File
@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Linq
{
internal class JPath
{
private readonly string _expression;
public List<object> Parts { get; private set; }
private int _currentIndex;
public JPath(string expression)
{
ValidationUtils.ArgumentNotNull(expression, "expression");
_expression = expression;
Parts = new List<object>();
ParseMain();
}
private void ParseMain()
{
int currentPartStartIndex = _currentIndex;
bool followingIndexer = false;
while (_currentIndex < _expression.Length)
{
char currentChar = _expression[_currentIndex];
switch (currentChar)
{
case '[':
case '(':
if (_currentIndex > currentPartStartIndex)
{
string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
Parts.Add(member);
}
ParseIndexer(currentChar);
currentPartStartIndex = _currentIndex + 1;
followingIndexer = true;
break;
case ']':
case ')':
throw new Exception("Unexpected character while parsing path: " + currentChar);
case '.':
if (_currentIndex > currentPartStartIndex)
{
string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
Parts.Add(member);
}
currentPartStartIndex = _currentIndex + 1;
followingIndexer = false;
break;
default:
if (followingIndexer)
throw new Exception("Unexpected character following indexer: " + currentChar);
break;
}
_currentIndex++;
}
if (_currentIndex - 1 > currentPartStartIndex)
{
string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
Parts.Add(member);
}
}
private void ParseIndexer(char indexerOpenChar)
{
_currentIndex++;
char indexerCloseChar = (indexerOpenChar == '[') ? ']' : ')';
int indexerStart = _currentIndex;
int indexerLength = 0;
bool indexerClosed = false;
while (_currentIndex < _expression.Length)
{
char currentCharacter = _expression[_currentIndex];
if (char.IsDigit(currentCharacter))
{
indexerLength++;
}
else if (currentCharacter == indexerCloseChar)
{
indexerClosed = true;
break;
}
else
{
throw new Exception("Unexpected character while parsing path indexer: " + currentCharacter);
}
_currentIndex++;
}
if (!indexerClosed)
throw new Exception("Path ended with open indexer. Expected " + indexerCloseChar);
if (indexerLength == 0)
throw new Exception("Empty path indexer.");
string indexer = _expression.Substring(indexerStart, indexerLength);
Parts.Add(Convert.ToInt32(indexer, CultureInfo.InvariantCulture));
}
internal JToken Evaluate(JToken root, bool errorWhenNoMatch)
{
JToken current = root;
foreach (object part in Parts)
{
string propertyName = part as string;
if (propertyName != null)
{
JObject o = current as JObject;
if (o != null)
{
current = o[propertyName];
if (current == null && errorWhenNoMatch)
throw new Exception("Property '{0}' does not exist on JObject.".FormatWith(CultureInfo.InvariantCulture, propertyName));
}
else
{
if (errorWhenNoMatch)
throw new Exception("Property '{0}' not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, propertyName, current.GetType().Name));
return null;
}
}
else
{
int index = (int) part;
JArray a = current as JArray;
if (a != null)
{
if (a.Count <= index)
{
if (errorWhenNoMatch)
throw new IndexOutOfRangeException("Index {0} outside the bounds of JArray.".FormatWith(CultureInfo.InvariantCulture, index));
return null;
}
current = a[index];
}
else
{
if (errorWhenNoMatch)
throw new Exception("Index {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, index, current.GetType().Name));
return null;
}
}
}
return current;
}
}
}
+11
View File
@@ -1095,5 +1095,16 @@ namespace Newtonsoft.Json.Linq
{
get { return _linePosition ?? 0; }
}
public JToken SelectToken(string path)
{
return SelectToken(path, false);
}
public JToken SelectToken(string path, bool errorWhenNoMatch)
{
JPath p = new JPath(path);
return p.Evaluate(this, errorWhenNoMatch);
}
}
}
@@ -60,6 +60,8 @@
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Converters\BinaryConverter.cs" />
<Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\DataSetConverter.cs" />
<Compile Include="Converters\DataTableConverter.cs" />
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="DateTimeOffset.cs" />
@@ -75,6 +77,7 @@
<Compile Include="Linq\ComponentModel\JTypeDescriptionProvider.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptor.cs" />
<Compile Include="Linq\IJEnumerable.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Linq\JTokenEqualityComparer.cs" />
<Compile Include="Linq\JTokenReader.cs" />
<Compile Include="Linq\JTokenType.cs" />
@@ -80,11 +80,14 @@
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Converters\BinaryConverter.cs" />
<Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\DataSetConverter.cs" />
<Compile Include="Converters\DataTableConverter.cs" />
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProvider.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptor.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
<Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="IJsonLineInfo.cs" />
@@ -52,6 +52,8 @@
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Converters\BinaryConverter.cs" />
<Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\DataSetConverter.cs" />
<Compile Include="Converters\DataTableConverter.cs" />
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
@@ -93,6 +95,7 @@
<Compile Include="Linq\JContainer.cs" />
<Compile Include="Linq\JEnumerable.cs" />
<Compile Include="Linq\JObject.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Linq\JProperty.cs" />
<Compile Include="Linq\JToken.cs" />
<Compile Include="Linq\JTokenEqualityComparer.cs" />
@@ -87,10 +87,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Converters\BinaryConverter.cs" />
<Compile Include="Converters\DataSetConverter.cs" />
<Compile Include="Converters\DataTableConverter.cs" />
<Compile Include="Converters\CustomCreationConverter.cs" />
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Serialization\ErrorEventArgs.cs" />
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
<Compile Include="Linq\ComponentModel\JTypeDescriptionProvider.cs" />
@@ -265,6 +265,8 @@ namespace Newtonsoft.Json.Schema
// TODO: include null
CurrentSchema.Type = JsonSchemaType.Array;
CurrentSchema.Id = GetTypeId(type, false);
JsonArrayAttribute arrayAttribute = JsonTypeReflector.GetJsonContainerAttribute(type) as JsonArrayAttribute;
bool allowNullItem = (arrayAttribute != null) ? arrayAttribute.AllowNullItems : false;
@@ -241,7 +241,7 @@ namespace Newtonsoft.Json.Serialization
}
}
#else
if (value is Guid || value is Type || value is Uri)
if (value is Guid || value is Type || value is Uri || value is TimeSpan)
{
s = value.ToString();
return true;
@@ -166,10 +166,12 @@ namespace Newtonsoft.Json.Utilities
if (initialValue is string)
{
if (targetType == typeof(Guid))
return new Guid((string)initialValue);
if (targetType == typeof(Uri))
if (targetType == typeof (Guid))
return new Guid((string) initialValue);
if (targetType == typeof (Uri))
return new Uri((string) initialValue);
if (targetType == typeof (TimeSpan))
return TimeSpan.Parse((string) initialValue);
}
#if !PocketPC
@@ -57,11 +57,15 @@ namespace Newtonsoft.Json.Utilities
case '\\':
writer.Write(@"\\");
break;
//case '<':
//case '>':
//case '\'':
// StringUtils.WriteCharAsUnicode(writer, c);
// break;
case '\u0085': // Next Line
writer.Write(@"\u0085");
break;
case '\u2028': // Line Separator
writer.Write(@"\u2028");
break;
case '\u2029': // Paragraph Separator
writer.Write(@"\u2029");
break;
case '\'':
// only escape if this charater is being used as the delimiter
writer.Write((delimiter == '\'') ? @"\'" : @"'");