Merge branch 'special-properties'

This commit is contained in:
James Newton-King
2014-03-01 18:39:42 +13:00
37 changed files with 983 additions and 179 deletions
@@ -57,6 +57,25 @@ namespace Newtonsoft.Json.Tests.Linq
[TestFixture]
public class JObjectTests : TestFixtureBase
{
[Test]
public void JObjectWithComments()
{
string json = @"{ /*comment2*/
""Name"": /*comment3*/ ""Apple"" /*comment4*/, /*comment5*/
""ExpiryDate"": ""\/Date(1230422400000)\/"",
""Price"": 3.99,
""Sizes"": /*comment6*/ [ /*comment7*/
""Small"", /*comment8*/
""Medium"" /*comment9*/,
/*comment10*/ ""Large""
/*comment11*/ ] /*comment12*/
} /*comment13*/";
JToken o = JToken.Parse(json);
Assert.AreEqual("Apple", (string) o["Name"]);
}
[Test]
public void WritePropertyWithNoValue()
{
@@ -44,6 +44,21 @@ namespace Newtonsoft.Json.Tests.Linq
[TestFixture]
public class JTokenReaderTest : TestFixtureBase
{
[Test]
public void ErrorTokenIndex()
{
JObject json = JObject.Parse(@"{""IntList"":[1, ""two""]}");
ExceptionAssert.Throws<Exception>(
"Could not convert string to integer: two. Path 'IntList[1]', line 1, position 20.",
() =>
{
JsonSerializer serializer = new JsonSerializer();
serializer.Deserialize<TraceTestObject>(json.CreateReader());
});
}
#if !NET20
[Test]
public void YahooFinance()
@@ -49,6 +49,24 @@ namespace Newtonsoft.Json.Tests.Linq
[TestFixture]
public class LinqToJsonTest : TestFixtureBase
{
[Test]
public void JPropertyPath()
{
JObject o = new JObject
{
{
"person",
new JObject
{
{ "$id", 1 }
}
}
};
JContainer idProperty = o["person"]["$id"].Parent;
Assert.AreEqual("person.$id", idProperty.Path);
}
[Test]
public void ForEach()
{
@@ -102,6 +102,7 @@
<Compile Include="Serialization\JsonPropertyCollectionTests.cs" />
<Compile Include="Serialization\NullValueHandlingTests.cs" />
<Compile Include="Serialization\ReferenceLoopHandlingTests.cs" />
<Compile Include="Serialization\SpecialPropertyHandlingTests.cs" />
<Compile Include="Serialization\TraceWriterTests.cs" />
<Compile Include="Serialization\WebApiIntegrationTests.cs" />
<Compile Include="TestObjects\Bar.cs" />
@@ -144,6 +144,7 @@
<Compile Include="Serialization\JsonPropertyCollectionTests.cs" />
<Compile Include="Serialization\NullValueHandlingTests.cs" />
<Compile Include="Serialization\ReferenceLoopHandlingTests.cs" />
<Compile Include="Serialization\SpecialPropertyHandlingTests.cs" />
<Compile Include="Serialization\TraceWriterTests.cs" />
<Compile Include="Serialization\WebApiIntegrationTests.cs" />
<Compile Include="TestObjects\Bar.cs" />
@@ -260,6 +260,7 @@
<Compile Include="Serialization\DynamicTests.cs" />
<Compile Include="Serialization\ImmutableCollectionsTests.cs" />
<Compile Include="Serialization\ReferenceLoopHandlingTests.cs" />
<Compile Include="Serialization\SpecialPropertyHandlingTests.cs" />
<Compile Include="Serialization\TraceWriterTests.cs" />
<Compile Include="Serialization\WebApiIntegrationTests.cs" />
<Compile Include="Serialization\JsonPropertyCollectionTests.cs" />
@@ -144,6 +144,7 @@
<Compile Include="Serialization\DynamicTests.cs" />
<Compile Include="Serialization\ImmutableCollectionsTests.cs" />
<Compile Include="Serialization\ReferenceLoopHandlingTests.cs" />
<Compile Include="Serialization\SpecialPropertyHandlingTests.cs" />
<Compile Include="Serialization\TraceWriterTests.cs" />
<Compile Include="Serialization\WebApiIntegrationTests.cs" />
<Compile Include="Serialization\JsonPropertyCollectionTests.cs" />
@@ -139,6 +139,7 @@
<Compile Include="Serialization\DefaultValueHandlingTests.cs" />
<Compile Include="Serialization\DynamicTests.cs" />
<Compile Include="Serialization\ReferenceLoopHandlingTests.cs" />
<Compile Include="Serialization\SpecialPropertyHandlingTests.cs" />
<Compile Include="Serialization\TraceWriterTests.cs" />
<Compile Include="Serialization\WebApiIntegrationTests.cs" />
<Compile Include="Serialization\JsonPropertyCollectionTests.cs" />
@@ -243,6 +243,7 @@
<Compile Include="Serialization\ReferenceLoopHandlingTests.cs" />
<Compile Include="Serialization\SerializationErrorHandlingTests.cs" />
<Compile Include="Serialization\SerializationEventAttributeTests.cs" />
<Compile Include="Serialization\SpecialPropertyHandlingTests.cs" />
<Compile Include="Serialization\TraceWriterTests.cs" />
<Compile Include="Serialization\TypeNameHandlingTests.cs" />
<Compile Include="Serialization\WebApiIntegrationTests.cs" />
@@ -75,4 +75,4 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.1.16929")]
[assembly: AssemblyFileVersion("6.0.1.17101")]
@@ -2140,15 +2140,13 @@ keyword such as type of business.""
});
Assert.AreEqual(@"{""DefaultConverter"":""\/Date(0)\/"",""MemberConverter"":""1970-01-01T00:00:00Z""}", json);
ExceptionAssert.Throws<JsonReaderException>(
"Could not convert string to DateTime: /Date(0)/. Path 'DefaultConverter', line 1, position 33.",
() =>
{
JsonConvert.DeserializeObject<MemberConverterClass>(json, new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
});
});
var m2 = JsonConvert.DeserializeObject<MemberConverterClass>(json, new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
});
Assert.AreEqual(new DateTime(1970, 1, 1), m2.DefaultConverter);
Assert.AreEqual(new DateTime(1970, 1, 1), m2.MemberConverter);
}
[Test]
@@ -2386,19 +2384,22 @@ keyword such as type of business.""
[Test]
public void DeserializeRequiredMembersClassNullRequiredValueProperty()
{
ExceptionAssert.Throws<JsonSerializationException>(
"Required property 'FirstName' expects a value but got null. Path '', line 6, position 2.",
() =>
{
string json = @"{
try
{
string json = @"{
""FirstName"": null,
""MiddleName"": null,
""LastName"": null,
""BirthDate"": ""\/Date(977309755000)\/""
}";
JsonConvert.DeserializeObject<RequiredMembersClass>(json);
});
JsonConvert.DeserializeObject<RequiredMembersClass>(json);
Assert.Fail();
}
catch (JsonSerializationException ex)
{
Assert.IsTrue(ex.Message.StartsWith("Required property 'FirstName' expects a value but got null. Path ''"));
}
}
[Test]
@@ -2424,16 +2425,19 @@ keyword such as type of business.""
[Test]
public void RequiredMembersClassMissingRequiredProperty()
{
ExceptionAssert.Throws<JsonSerializationException>(
"Required property 'LastName' not found in JSON. Path '', line 3, position 2.",
() =>
{
string json = @"{
try
{
string json = @"{
""FirstName"": ""Bob""
}";
JsonConvert.DeserializeObject<RequiredMembersClass>(json);
});
JsonConvert.DeserializeObject<RequiredMembersClass>(json);
Assert.Fail();
}
catch (JsonSerializationException ex)
{
Assert.IsTrue(ex.Message.StartsWith("Required property 'LastName' not found in JSON. Path ''"));
}
}
[Test]
@@ -2672,10 +2676,17 @@ keyword such as type of business.""
[Test]
public void RequiredWhenUsingConstructor()
{
string json = "{ 'testProperty1': 'value' }";
try
{
string json = "{ 'testProperty1': 'value' }";
JsonConvert.DeserializeObject<ConstructorAndRequiredTestClass>(json);
ExceptionAssert.Throws<JsonSerializationException>("Required property 'TestProperty2' not found in JSON. Path '', line 1, position 28.",
() => JsonConvert.DeserializeObject<ConstructorAndRequiredTestClass>(json));
Assert.Fail();
}
catch (JsonSerializationException ex)
{
Assert.IsTrue(ex.Message.StartsWith("Required property 'TestProperty2' not found in JSON. Path ''"));
}
}
[Test]
@@ -2969,16 +2980,16 @@ keyword such as type of business.""
[Test]
public void TypedObjectDeserializationWithComments()
{
string json = @"/*comment*/ { /*comment*/
""Name"": /*comment*/ ""Apple"" /*comment*/, /*comment*/
string json = @"/*comment1*/ { /*comment2*/
""Name"": /*comment3*/ ""Apple"" /*comment4*/, /*comment5*/
""ExpiryDate"": ""\/Date(1230422400000)\/"",
""Price"": 3.99,
""Sizes"": /*comment*/ [ /*comment*/
""Small"", /*comment*/
""Medium"" /*comment*/,
/*comment*/ ""Large""
/*comment*/ ] /*comment*/
} /*comment*/";
""Sizes"": /*comment6*/ [ /*comment7*/
""Small"", /*comment8*/
""Medium"" /*comment9*/,
/*comment10*/ ""Large""
/*comment11*/ ] /*comment12*/
} /*comment13*/";
Product deserializedProduct = (Product)JsonConvert.DeserializeObject(json, typeof(Product));
@@ -3392,11 +3403,17 @@ Path '', line 1, position 1.",
{
string json = @"{}";
ExceptionAssert.Throws<JsonSerializationException>(
@"Cannot deserialize the current JSON object (e.g. {""name"":""value""}) into type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
try
{
JsonConvert.DeserializeObject<List<Person>>(json);
Assert.Fail();
}
catch (JsonSerializationException ex)
{
Assert.IsTrue(ex.Message.StartsWith(@"Cannot deserialize the current JSON object (e.g. {""name"":""value""}) into type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path '', line 1, position 2.",
() => { JsonConvert.DeserializeObject<List<Person>>(json); });
Path ''"));
}
}
[Test]
@@ -3615,17 +3632,21 @@ Path '', line 1, position 2.",
[Test]
public void DeserializePersonKeyedDictionary()
{
ExceptionAssert.Throws<JsonSerializationException>("Could not convert string 'Newtonsoft.Json.Tests.TestObjects.Person' to dictionary key type 'Newtonsoft.Json.Tests.TestObjects.Person'. Create a TypeConverter to convert from the string to the key type object. Path 'Newtonsoft.Json.Tests.TestObjects.Person', line 2, position 46.",
() =>
{
string json =
@"{
try
{
string json =
@"{
""Newtonsoft.Json.Tests.TestObjects.Person"": 1,
""Newtonsoft.Json.Tests.TestObjects.Person"": 2
}";
JsonConvert.DeserializeObject<Dictionary<Person, int>>(json);
});
JsonConvert.DeserializeObject<Dictionary<Person, int>>(json);
Assert.Fail();
}
catch (JsonSerializationException ex)
{
Assert.IsTrue(ex.Message.StartsWith("Could not convert string 'Newtonsoft.Json.Tests.TestObjects.Person' to dictionary key type 'Newtonsoft.Json.Tests.TestObjects.Person'. Create a TypeConverter to convert from the string to the key type object. Path 'Newtonsoft.Json.Tests.TestObjects.Person'"));
}
}
[Test]
@@ -3899,7 +3920,11 @@ Path '', line 1, position 2.",
string json = "{'$id':'1',key1:'value1',key2:'value2',key3:'value3'}";
ExceptionAssert.Throws<JsonSerializationException>("Cannot preserve reference to readonly dictionary, or dictionary created from a non-default constructor: Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+DictionaryWithNoDefaultConstructor. Path 'key1', line 1, position 16.",
() => JsonConvert.DeserializeObject<DictionaryWithNoDefaultConstructor>(json, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All }));
() => JsonConvert.DeserializeObject<DictionaryWithNoDefaultConstructor>(json, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.Default
}));
}
public class DictionaryWithNoDefaultConstructor : Dictionary<string, string>
@@ -5045,7 +5070,10 @@ To fix this error either change the environment to be fully trusted, change the
child.Add("Name", "Isabell");
child.Add("Father", reference);
var json = JsonConvert.SerializeObject(child);
string json = JsonConvert.SerializeObject(child);
Console.WriteLine(json);
Dictionary<string, object> result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
Assert.AreEqual(3, result.Count);
@@ -5488,7 +5516,14 @@ To fix this error either change the environment to be fully trusted, change the
});
Assert.AreEqual("{\"Offset\":\"2000-01-01T00:00:00+06:00\"}", serializeObject);
var deserializeObject = JsonConvert.DeserializeObject<TimeZoneOffsetObject>(serializeObject);
JsonTextReader reader = new JsonTextReader(new StringReader(serializeObject));
reader.DateParseHandling = DateParseHandling.None;
JsonSerializer serializer = new JsonSerializer();
var deserializeObject = serializer.Deserialize<TimeZoneOffsetObject>(reader);
Assert.AreEqual(TimeSpan.FromHours(6), deserializeObject.Offset.Offset);
Assert.AreEqual(new DateTime(2000, 1, 1), deserializeObject.Offset.Date);
}
@@ -5509,7 +5544,14 @@ To fix this error either change the environment to be fully trusted, change the
}, Formatting.None, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat });
Assert.AreEqual("{\"Offset\":\"\\/Date(946663200000+0600)\\/\"}", serializeObject);
var deserializeObject = JsonConvert.DeserializeObject<TimeZoneOffsetObject>(serializeObject);
JsonTextReader reader = new JsonTextReader(new StringReader(serializeObject));
JsonSerializer serializer = new JsonSerializer();
serializer.DateParseHandling = DateParseHandling.None;
var deserializeObject = serializer.Deserialize<TimeZoneOffsetObject>(reader);
Assert.AreEqual(TimeSpan.FromHours(6), deserializeObject.Offset.Offset);
Assert.AreEqual(new DateTime(2000, 1, 1), deserializeObject.Offset.Date);
}
@@ -5604,7 +5646,12 @@ To fix this error either change the environment to be fully trusted, change the
public void DeserializeDecimalPropertyExact()
{
string json = "{Amount:123456789876543.21}";
Invoice i = JsonConvert.DeserializeObject<Invoice>(json);
JsonTextReader reader = new JsonTextReader(new StringReader(json));
reader.FloatParseHandling = FloatParseHandling.Decimal;
JsonSerializer serializer = new JsonSerializer();
Invoice i = serializer.Deserialize<Invoice>(reader);
Assert.AreEqual(123456789876543.21m, i.Amount);
}
@@ -5620,7 +5667,12 @@ To fix this error either change the environment to be fully trusted, change the
public void DeserializeDecimalDictionaryExact()
{
string json = "{'Value':123456789876543.21}";
IDictionary<string, decimal> d = JsonConvert.DeserializeObject<IDictionary<string, decimal>>(json);
JsonTextReader reader = new JsonTextReader(new StringReader(json));
reader.FloatParseHandling = FloatParseHandling.Decimal;
JsonSerializer serializer = new JsonSerializer();
IDictionary<string, decimal> d = serializer.Deserialize<IDictionary<string, decimal>>(reader);
Assert.AreEqual(123456789876543.21m, d["Value"]);
}
@@ -5835,11 +5887,11 @@ To fix this error either change the environment to be fully trusted, change the
}
[Test]
public void OnError()
public void DeserializeMinValueDecimal()
{
var data = new DecimalTest(decimal.MinValue);
var json = JsonConvert.SerializeObject(data);
var obj = JsonConvert.DeserializeObject<DecimalTest>(json);
var obj = JsonConvert.DeserializeObject<DecimalTest>(json, new JsonSerializerSettings { SpecialPropertyHandling = SpecialPropertyHandling.Default });
Assert.AreEqual(decimal.MinValue, obj.Value);
}
@@ -6998,8 +7050,8 @@ To fix this error either change the environment to be fully trusted, change the
[Test]
public void DeserializeUnexpectedEndInt()
{
ExceptionAssert.Throws<JsonSerializationException>(
"Unexpected end when setting PreProperty's value. Path 'PreProperty', line 2, position 18.",
ExceptionAssert.Throws<JsonException>(
null,
() =>
{
string json = @"{
@@ -7436,10 +7488,10 @@ Parameter name: value",
Assert.IsNotNull(o);
Assert.AreEqual(4, errors.Count);
Assert.AreEqual("Required property 'NonAttributeProperty' not found in JSON. Path '', line 1, position 2.", errors[0]);
Assert.AreEqual("Required property 'UnsetProperty' not found in JSON. Path '', line 1, position 2.", errors[1]);
Assert.AreEqual("Required property 'AllowNullProperty' not found in JSON. Path '', line 1, position 2.", errors[2]);
Assert.AreEqual("Required property 'AlwaysProperty' not found in JSON. Path '', line 1, position 2.", errors[3]);
Assert.IsTrue(errors[0].StartsWith("Required property 'NonAttributeProperty' not found in JSON. Path ''"));
Assert.IsTrue(errors[1].StartsWith("Required property 'UnsetProperty' not found in JSON. Path ''"));
Assert.IsTrue(errors[2].StartsWith("Required property 'AllowNullProperty' not found in JSON. Path ''"));
Assert.IsTrue(errors[3].StartsWith("Required property 'AlwaysProperty' not found in JSON. Path ''"));
}
[Test]
@@ -7461,9 +7513,9 @@ Parameter name: value",
Assert.IsNotNull(o);
Assert.AreEqual(3, errors.Count);
Assert.AreEqual("Required property 'NonAttributeProperty' expects a value but got null. Path '', line 1, position 97.", errors[0]);
Assert.AreEqual("Required property 'UnsetProperty' expects a value but got null. Path '', line 1, position 97.", errors[1]);
Assert.AreEqual("Required property 'AlwaysProperty' expects a value but got null. Path '', line 1, position 97.", errors[2]);
Assert.IsTrue(errors[0].StartsWith("Required property 'NonAttributeProperty' expects a value but got null. Path ''"));
Assert.IsTrue(errors[1].StartsWith("Required property 'UnsetProperty' expects a value but got null. Path ''"));
Assert.IsTrue(errors[2].StartsWith("Required property 'AlwaysProperty' expects a value but got null. Path ''"));
}
[Test]
@@ -8593,8 +8645,8 @@ Parameter name: value",
{
string json = @"{""Before"":""Before!"",""Coordinates"":[/*hi*/[/*hi*/[1/*hi*/,/*hi*/1/*hi*/,1]/*hi*/,/*hi*/[1,1";
ExceptionAssert.Throws<JsonSerializationException>(
"Unexpected end when deserializing array. Path 'Coordinates[0][1][1]', line 1, position 90.",
ExceptionAssert.Throws<JsonException>(
null,
() => JsonConvert.DeserializeObject<Array3D>(json));
}
@@ -8603,8 +8655,8 @@ Parameter name: value",
{
string json = @"{""Before"":""Before!"",""Coordinates"":[/*hi*/[/*hi*/";
ExceptionAssert.Throws<JsonSerializationException>(
"Unexpected end when deserializing array. Path 'Coordinates[0]', line 1, position 48.",
ExceptionAssert.Throws<JsonException>(
null,
() => JsonConvert.DeserializeObject<Array3D>(json));
}
@@ -295,7 +295,11 @@ namespace Newtonsoft.Json.Tests.Serialization
() =>
{
JsonConvert.DeserializeObject<string[][]>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.Default
});
});
}
@@ -1063,7 +1067,10 @@ namespace Newtonsoft.Json.Tests.Serialization
ExceptionAssert.Throws<JsonSerializationException>(
"Error reading object reference '1'. Path 'Data.Prop2.MyProperty', line 9, position 20.",
() => JsonConvert.DeserializeObject<PropertyItemIsReferenceObject>(json));
() => JsonConvert.DeserializeObject<PropertyItemIsReferenceObject>(json, new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.Default
}));
}
}
@@ -407,6 +407,7 @@ namespace Newtonsoft.Json.Tests.Serialization
string json = "{}";
List<string> errors = new List<string>();
JsonSerializer serializer = new JsonSerializer();
serializer.SpecialPropertyHandling = SpecialPropertyHandling.Default;
serializer.Error += delegate(object sender, ErrorEventArgs args)
{
errors.Add(args.ErrorContext.Path + " - " + args.ErrorContext.Member + " - " + args.ErrorContext.Error.Message);
@@ -415,8 +416,8 @@ namespace Newtonsoft.Json.Tests.Serialization
serializer.Deserialize(new JsonTextReader(new StringReader(json)), typeof(MyTypeWithRequiredMembers));
Assert.AreEqual(2, errors.Count);
Assert.AreEqual(" - Required1 - Required property 'Required1' not found in JSON. Path '', line 1, position 2.", errors[0]);
Assert.AreEqual(" - Required2 - Required property 'Required2' not found in JSON. Path '', line 1, position 2.", errors[1]);
Assert.IsTrue(errors[0].StartsWith(" - Required1 - Required property 'Required1' not found in JSON. Path '', line 1, position 2."));
Assert.IsTrue(errors[1].StartsWith(" - Required2 - Required property 'Required2' not found in JSON. Path '', line 1, position 2."));
}
[Test]
@@ -539,6 +540,7 @@ namespace Newtonsoft.Json.Tests.Serialization
"{'badarray':[0,x,2],'goodarray':[0,1,2]}",
new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.Default,
Error = (sender, arg) =>
{
errors.Add(arg.ErrorContext.Error.Message);
@@ -565,7 +567,11 @@ namespace Newtonsoft.Json.Tests.Serialization
const int maxDepth = 256;
using (var jsonTextReader = new JsonTextReader(new StringReader(input)) { MaxDepth = maxDepth })
{
JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings { MaxDepth = maxDepth });
JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings
{
MaxDepth = maxDepth,
SpecialPropertyHandling = SpecialPropertyHandling.Default
});
jsonSerializer.Error += (sender, e) =>
{
errors.Add(e.ErrorContext.Error.Message);
@@ -595,7 +601,7 @@ namespace Newtonsoft.Json.Tests.Serialization
const int maxDepth = 256;
using (var jsonTextReader = new JsonTextReader(new StringReader(input)) { MaxDepth = maxDepth })
{
JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings { MaxDepth = maxDepth });
JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings { MaxDepth = maxDepth, SpecialPropertyHandling = SpecialPropertyHandling.Default });
jsonSerializer.Error += (sender, e) =>
{
errors.Add(e.ErrorContext.Error.Message);
@@ -634,7 +640,8 @@ namespace Newtonsoft.Json.Tests.Serialization
{
errors.Add(e.ErrorContext.Error.Message);
e.ErrorContext.Handled = true;
}
},
SpecialPropertyHandling = SpecialPropertyHandling.Default
});
Assert.AreEqual(true, newDynamicObject.Explicit);
@@ -0,0 +1,373 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Tests.TestObjects;
using Newtonsoft.Json.Utilities;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests.Serialization
{
[TestFixture]
public class SpecialPropertyHandlingTests : TestFixtureBase
{
[Test]
public void DeserializeArraysWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}";
ExceptionAssert.Throws<JsonSerializationException>(
@"Cannot preserve reference to array or readonly list, or list created from a non-default constructor: System.String[][]. Path '$values', line 3, position 15.",
() =>
{
JsonConvert.DeserializeObject<string[][]>(json,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
});
}
#if !NETFX_CORE
[Test]
public void SerializeDeserialize_DictionaryContextContainsGuid_DeserializesItemAsGuid()
{
const string contextKey = "k1";
var someValue = Guid.NewGuid();
Dictionary<string, Guid> inputContext = new Dictionary<string, Guid>();
inputContext.Add(contextKey, someValue);
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
};
string serializedString = JsonConvert.SerializeObject(inputContext, jsonSerializerSettings);
Console.WriteLine(serializedString);
var deserializedObject = (Dictionary<string, Guid>)JsonConvert.DeserializeObject(serializedString, jsonSerializerSettings);
Assert.AreEqual(someValue, deserializedObject[contextKey]);
}
#endif
[Test]
public void DeserializeGuid()
{
Item expected = new Item()
{
SourceTypeID = new Guid("d8220a4b-75b1-4b7a-8112-b7bdae956a45"),
BrokerID = new Guid("951663c4-924e-4c86-a57a-7ed737501dbd"),
Latitude = 33.657145,
Longitude = -117.766684,
TimeStamp = new DateTime(2000, 3, 1, 23, 59, 59, DateTimeKind.Utc),
Payload = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
};
string jsonString = JsonConvert.SerializeObject(expected, Formatting.Indented);
Assert.AreEqual(@"{
""SourceTypeID"": ""d8220a4b-75b1-4b7a-8112-b7bdae956a45"",
""BrokerID"": ""951663c4-924e-4c86-a57a-7ed737501dbd"",
""Latitude"": 33.657145,
""Longitude"": -117.766684,
""TimeStamp"": ""2000-03-01T23:59:59Z"",
""Payload"": {
""$type"": ""System.Byte[], mscorlib"",
""$value"": ""AAECAwQFBgcICQ==""
}
}", jsonString);
Item actual = JsonConvert.DeserializeObject<Item>(jsonString, new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
Assert.AreEqual(new Guid("d8220a4b-75b1-4b7a-8112-b7bdae956a45"), actual.SourceTypeID);
Assert.AreEqual(new Guid("951663c4-924e-4c86-a57a-7ed737501dbd"), actual.BrokerID);
byte[] bytes = (byte[])actual.Payload;
CollectionAssert.AreEquivalent(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, bytes);
}
[Test]
public void DeserializeListsWithPreserveObjectReferences()
{
string json = @"{
""$id"": ""1"",
""$values"": [
null,
{
""$id"": ""2"",
""$values"": [
null
]
},
{
""$id"": ""3"",
""$values"": [
{
""$id"": ""4"",
""$values"": [
{
""$ref"": ""1""
}
]
}
]
}
]
}";
PreserveReferencesHandlingTests.CircularList circularList = JsonConvert.DeserializeObject<PreserveReferencesHandlingTests.CircularList>(json,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
Assert.AreEqual(3, circularList.Count);
Assert.AreEqual(null, circularList[0]);
Assert.AreEqual(1, circularList[1].Count);
Assert.AreEqual(1, circularList[2].Count);
Assert.AreEqual(1, circularList[2][0].Count);
Assert.IsTrue(ReferenceEquals(circularList, circularList[2][0][0]));
}
[Test]
public void DeserializeTypeNameOnly()
{
string json = @"{
""$id"": ""1"",
""$type"": ""Newtonsoft.Json.Tests.TestObjects.Employee"",
""Name"": ""Name!"",
""Manager"": null
}";
ExceptionAssert.Throws<JsonSerializationException>(
"Type specified in JSON 'Newtonsoft.Json.Tests.TestObjects.Employee' was not resolved. Path '$type', line 3, position 56.",
() =>
{
JsonConvert.DeserializeObject(json, null, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
});
}
[Test]
public void SerializeRefNull()
{
var reference = new Dictionary<string, object>();
reference.Add("blah", "blah!");
reference.Add("$ref", null);
reference.Add("$id", null);
var child = new Dictionary<string, object>();
child.Add("_id", 2);
child.Add("Name", "Isabell");
child.Add("Father", reference);
string json = JsonConvert.SerializeObject(child, Formatting.Indented);
Console.WriteLine(json);
Dictionary<string, object> result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
Assert.AreEqual(3, result.Count);
Assert.AreEqual(1, ((JObject)result["Father"]).Count);
Assert.AreEqual("blah!", (string)((JObject)result["Father"])["blah"]);
}
[Test]
public void DeserializeEmployeeReference()
{
string json = @"[
{
""Name"": ""Mike Manager"",
""$id"": ""1"",
""Manager"": null
},
{
""Name"": ""Joe User"",
""$id"": ""2"",
""Manager"": {
""$ref"": ""1""
}
}
]";
List<EmployeeReference> employees = JsonConvert.DeserializeObject<List<EmployeeReference>>(json, new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
Assert.AreEqual(2, employees.Count);
Assert.AreEqual("Mike Manager", employees[0].Name);
Assert.AreEqual("Joe User", employees[1].Name);
Assert.AreEqual(employees[0], employees[1].Manager);
}
[Test]
public void DeserializeFromJToken()
{
string json = @"[
{
""Name"": ""Mike Manager"",
""$id"": ""1"",
""Manager"": null
},
{
""Name"": ""Joe User"",
""$id"": ""2"",
""Manager"": {
""$ref"": ""1""
}
}
]";
JToken t1 = JToken.Parse(json);
JToken t2 = t1.CloneToken();
List<EmployeeReference> employees = t1.ToObject<List<EmployeeReference>>(JsonSerializer.Create(new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
}));
Assert.AreEqual(2, employees.Count);
Assert.AreEqual("Mike Manager", employees[0].Name);
Assert.AreEqual("Joe User", employees[1].Name);
Assert.AreEqual(employees[0], employees[1].Manager);
Assert.IsTrue(JToken.DeepEquals(t1, t2));
}
#if !(PORTABLE || PORTABLE40)
[Test]
public void DeserializeGenericObjectListWithTypeName()
{
string employeeRef = typeof(EmployeeReference).AssemblyQualifiedName;
string personRef = typeof(Person).AssemblyQualifiedName;
string json = @"[
{
""Name"": ""Bob"",
""$id"": ""1"",
""$type"": """ + employeeRef + @""",
""Manager"": {
""$id"": ""2"",
""$type"": """ + employeeRef + @""",
""Name"": ""Frank"",
""Manager"": null
}
},
{
""Name"": null,
""$type"": """ + personRef + @""",
""BirthDate"": ""\/Date(978134400000)\/"",
""LastModified"": ""\/Date(978134400000)\/""
},
""String!"",
-2147483648
]";
List<object> values = (List<object>)JsonConvert.DeserializeObject(json, typeof(List<object>), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
Assert.AreEqual(4, values.Count);
EmployeeReference e = (EmployeeReference)values[0];
Person p = (Person)values[1];
Assert.AreEqual("Bob", e.Name);
Assert.AreEqual("Frank", e.Manager.Name);
Assert.AreEqual(null, p.Name);
Assert.AreEqual(new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc), p.BirthDate);
Assert.AreEqual(new DateTime(2000, 12, 30, 0, 0, 0, DateTimeKind.Utc), p.LastModified);
Assert.AreEqual("String!", values[2]);
Assert.AreEqual((long)int.MinValue, values[3]);
}
[Test]
public void WriteListTypeNameForProperty()
{
string listRef = ReflectionUtils.GetTypeName(typeof(List<int>), FormatterAssemblyStyle.Simple, null);
TypeNameHandlingTests.TypeNameProperty typeNameProperty = new TypeNameHandlingTests.TypeNameProperty
{
Name = "Name!",
Value = new List<int> { 1, 2, 3, 4, 5 }
};
string json = JsonConvert.SerializeObject(typeNameProperty, Formatting.Indented);
Assert.AreEqual(@"{
""Name"": ""Name!"",
""Value"": {
""$type"": """ + listRef + @""",
""$values"": [
1,
2,
3,
4,
5
]
}
}", json);
TypeNameHandlingTests.TypeNameProperty deserialized = JsonConvert.DeserializeObject<TypeNameHandlingTests.TypeNameProperty>(json, new JsonSerializerSettings
{
SpecialPropertyHandling = SpecialPropertyHandling.ReadAhead
});
Assert.AreEqual("Name!", deserialized.Name);
CustomAssert.IsInstanceOfType(typeof(List<int>), deserialized.Value);
List<int> nested = (List<int>)deserialized.Value;
Assert.AreEqual(5, nested.Count);
Assert.AreEqual(1, nested[0]);
Assert.AreEqual(2, nested[1]);
Assert.AreEqual(3, nested[2]);
Assert.AreEqual(4, nested[3]);
Assert.AreEqual(5, nested[4]);
}
#endif
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using Newtonsoft.Json.Linq;
#if !(NET20 || NET35 || PORTABLE || PORTABLE40)
using System.Numerics;
#endif
@@ -135,7 +136,12 @@ Newtonsoft.Json Error: 0 : Error!
JsonConvert.DeserializeObject<Staff>(
json,
new JsonSerializerSettings { TraceWriter = traceWriter, Converters = { new JavaScriptDateTimeConverter() } });
new JsonSerializerSettings
{
TraceWriter = traceWriter,
Converters = { new JavaScriptDateTimeConverter() },
SpecialPropertyHandling = SpecialPropertyHandling.Default
});
Console.WriteLine(traceWriter);
// 2012-11-11T12:08:42.761 Info Started serializing Newtonsoft.Json.Tests.Serialization.Staff. Path ''.
@@ -270,15 +276,15 @@ Newtonsoft.Json Error: 0 : Error!
Assert.AreEqual("Started deserializing Newtonsoft.Json.Tests.Serialization.TraceTestObject. Path 'IntList', line 2, position 13.", traceWriter.TraceRecords[0].Message);
Assert.AreEqual("Started deserializing System.Collections.Generic.IList`1[System.Int32]. Path 'IntList', line 2, position 15.", traceWriter.TraceRecords[1].Message);
Assert.AreEqual("Finished deserializing System.Collections.Generic.IList`1[System.Int32]. Path 'IntList', line 5, position 4.", traceWriter.TraceRecords[2].Message);
Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Finished deserializing System.Collections.Generic.IList`1[System.Int32]. Path 'IntList'"));
Assert.AreEqual("Started deserializing System.String[]. Path 'StringArray', line 6, position 19.", traceWriter.TraceRecords[3].Message);
Assert.AreEqual("Finished deserializing System.String[]. Path 'StringArray', line 9, position 4.", traceWriter.TraceRecords[4].Message);
Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.String[]. Path 'StringArray'"));
Assert.AreEqual("Deserializing System.Version using a non-default constructor 'Void .ctor(Int32, Int32, Int32, Int32)'. Path 'Version.Major', line 11, position 13.", traceWriter.TraceRecords[5].Message);
Assert.AreEqual("Started deserializing System.Version. Path 'Version', line 17, position 4.", traceWriter.TraceRecords[6].Message);
Assert.AreEqual("Finished deserializing System.Version. Path 'Version', line 17, position 4.", traceWriter.TraceRecords[7].Message);
Assert.IsTrue(traceWriter.TraceRecords[6].Message.StartsWith("Started deserializing System.Version. Path 'Version'"));
Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Finished deserializing System.Version. Path 'Version'"));
Assert.AreEqual("Started deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary.1', line 19, position 9.", traceWriter.TraceRecords[8].Message);
Assert.AreEqual("Finished deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary', line 22, position 4.", traceWriter.TraceRecords[9].Message);
Assert.AreEqual("Finished deserializing Newtonsoft.Json.Tests.Serialization.TraceTestObject. Path '', line 23, position 2.", traceWriter.TraceRecords[10].Message);
Assert.IsTrue(traceWriter.TraceRecords[9].Message.StartsWith("Finished deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary'"));
Assert.IsTrue(traceWriter.TraceRecords[10].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.Serialization.TraceTestObject. Path ''"));
Assert.IsFalse(traceWriter.TraceRecords.Any(r => r.Level == TraceLevel.Verbose));
}
@@ -397,12 +403,13 @@ Newtonsoft.Json Error: 0 : Error!
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.Default,
TraceWriter = traceWriter
});
Assert.IsTrue(traceWriter.TraceRecords.Any(r => r.Message == "Read object reference Id '1' for Newtonsoft.Json.Tests.Serialization.PreserveReferencesHandlingTests+CircularDictionary. Path 'other', line 3, position 11."));
Assert.IsTrue(traceWriter.TraceRecords.Any(r => r.Message == "Read object reference Id '2' for Newtonsoft.Json.Tests.Serialization.PreserveReferencesHandlingTests+CircularDictionary. Path 'other.blah', line 5, position 12."));
Assert.IsTrue(traceWriter.TraceRecords.Any(r => r.Message == "Resolved object reference '1' to Newtonsoft.Json.Tests.Serialization.PreserveReferencesHandlingTests+CircularDictionary. Path 'self', line 9, position 4."));
Assert.IsTrue(traceWriter.TraceRecords.Any(r => r.Message.StartsWith("Resolved object reference '1' to Newtonsoft.Json.Tests.Serialization.PreserveReferencesHandlingTests+CircularDictionary. Path 'self'")));
}
[Test]
@@ -516,6 +523,7 @@ Newtonsoft.Json Error: 0 : Error!
JsonConvert.DeserializeObject(json, null, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
SpecialPropertyHandling = SpecialPropertyHandling.Default,
TraceWriter = traceWriter
});
@@ -523,12 +531,12 @@ Newtonsoft.Json Error: 0 : Error!
Assert.AreEqual("Started deserializing System.Collections.Generic.List`1[System.Object]. Path '$values', line 3, position 15.", traceWriter.TraceRecords[1].Message);
Assert.AreEqual("Resolved type 'System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]], mscorlib' to System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0].$type', line 5, position 120.", traceWriter.TraceRecords[2].Message);
Assert.AreEqual("Started deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0].key!', line 6, position 14.", traceWriter.TraceRecords[3].Message);
Assert.AreEqual("Finished deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0]', line 7, position 6.", traceWriter.TraceRecords[4].Message);
Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0]'"));
Assert.AreEqual("Resolved type 'System.Version, mscorlib' to System.Version. Path '$values[1].$type', line 9, position 42.", traceWriter.TraceRecords[5].Message);
Assert.AreEqual("Deserializing System.Version using a non-default constructor 'Void .ctor(Int32, Int32, Int32, Int32)'. Path '$values[1].Major', line 10, position 15.", traceWriter.TraceRecords[6].Message);
Assert.AreEqual("Started deserializing System.Version. Path '$values[1]', line 16, position 6.", traceWriter.TraceRecords[7].Message);
Assert.AreEqual("Finished deserializing System.Version. Path '$values[1]', line 16, position 6.", traceWriter.TraceRecords[8].Message);
Assert.AreEqual("Finished deserializing System.Collections.Generic.List`1[System.Object]. Path '$values', line 17, position 4.", traceWriter.TraceRecords[9].Message);
Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Started deserializing System.Version. Path '$values[1]'"));
Assert.IsTrue(traceWriter.TraceRecords[8].Message.StartsWith("Finished deserializing System.Version. Path '$values[1]'"));
Assert.IsTrue(traceWriter.TraceRecords[9].Message.StartsWith("Finished deserializing System.Collections.Generic.List`1[System.Object]. Path '$values'"));
}
#if !(NETFX_CORE || PORTABLE || PORTABLE40)
@@ -552,7 +560,7 @@ Newtonsoft.Json Error: 0 : Error!
});
});
Assert.AreEqual("Deserializing System.Exception using ISerializable constructor. Path '', line 1, position 2.", traceWriter.TraceRecords[0].Message);
Assert.IsTrue(traceWriter.TraceRecords[0].Message.StartsWith("Deserializing System.Exception using ISerializable constructor. Path ''"));
Assert.AreEqual(TraceLevel.Info, traceWriter.TraceRecords[0].Level);
Assert.AreEqual("Error deserializing System.Exception. Member 'ClassName' was not found. Path '', line 1, position 2.", traceWriter.TraceRecords[1].Message);
Assert.AreEqual(TraceLevel.Error, traceWriter.TraceRecords[1].Level);
@@ -576,7 +584,7 @@ Newtonsoft.Json Error: 0 : Error!
Assert.AreEqual("Started deserializing Newtonsoft.Json.Tests.TestObjects.Person. Path 'MissingMemberProperty', line 1, position 25.", traceWriter.TraceRecords[0].Message);
Assert.AreEqual("Could not find member 'MissingMemberProperty' on Newtonsoft.Json.Tests.TestObjects.Person. Path 'MissingMemberProperty', line 1, position 25.", traceWriter.TraceRecords[1].Message);
Assert.AreEqual("Finished deserializing Newtonsoft.Json.Tests.TestObjects.Person. Path '', line 1, position 30.", traceWriter.TraceRecords[2].Message);
Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.TestObjects.Person. Path ''"));
}
[Test]
@@ -604,8 +612,8 @@ Newtonsoft.Json Error: 0 : Error!
Assert.AreEqual("Deserializing System.Version using a non-default constructor 'Void .ctor(Int32, Int32, Int32, Int32)'. Path 'Major', line 2, position 11.", traceWriter.TraceRecords[0].Message);
Assert.AreEqual("Could not find member 'MissingMemberProperty' on System.Version. Path 'MissingMemberProperty', line 8, position 32.", traceWriter.TraceRecords[1].Message);
Assert.AreEqual("Started deserializing System.Version. Path '', line 9, position 2.", traceWriter.TraceRecords[2].Message);
Assert.AreEqual("Finished deserializing System.Version. Path '', line 9, position 2.", traceWriter.TraceRecords[3].Message);
Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Started deserializing System.Version. Path ''"));
Assert.IsTrue(traceWriter.TraceRecords[3].Message.StartsWith("Finished deserializing System.Version. Path ''"));
}
[Test]
@@ -673,7 +681,7 @@ Newtonsoft.Json Error: 0 : Error!
SpecifiedTestClass deserialized = JsonConvert.DeserializeObject<SpecifiedTestClass>(json, new JsonSerializerSettings { TraceWriter = traceWriter });
Assert.AreEqual("Started deserializing Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass. Path 'Age', line 2, position 9.", traceWriter.TraceRecords[0].Message);
Assert.AreEqual("Finished deserializing Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass. Path '', line 3, position 2.", traceWriter.TraceRecords[1].Message);
Assert.IsTrue(traceWriter.TraceRecords[1].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass. Path ''"));
Assert.IsNull(deserialized.Name);
Assert.IsFalse(deserialized.NameSpecified);
@@ -707,7 +715,7 @@ Newtonsoft.Json Error: 0 : Error!
Assert.AreEqual("IsSpecified for property 'Name' on Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass set to true. Path 'Name', line 2, position 18.", traceWriter.TraceRecords[1].Message);
Assert.AreEqual("IsSpecified for property 'Weight' on Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass set to true. Path 'Weight', line 4, position 14.", traceWriter.TraceRecords[2].Message);
Assert.AreEqual("IsSpecified for property 'Height' on Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass set to true. Path 'Height', line 5, position 14.", traceWriter.TraceRecords[3].Message);
Assert.AreEqual("Finished deserializing Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass. Path '', line 7, position 2.", traceWriter.TraceRecords[4].Message);
Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.Serialization.SpecifiedTestClass. Path ''"));
Assert.AreEqual("James", deserialized.Name);
Assert.IsTrue(deserialized.NameSpecified);
@@ -122,6 +122,7 @@ namespace Newtonsoft.Json.Tests.Serialization
{
var reader = new JsonTextReader(new StringReader(sb.ToString()));
var ser = new JsonSerializer();
ser.SpecialPropertyHandling = SpecialPropertyHandling.Default;
ser.Deserialize<bool>(reader);
});
}
@@ -1591,6 +1592,8 @@ namespace Newtonsoft.Json.Tests.Serialization
};
string serializedString = JsonConvert.SerializeObject(inputContext, jsonSerializerSettings);
Console.WriteLine(serializedString);
var deserializedObject = (Dictionary<string, Guid>)JsonConvert.DeserializeObject(serializedString, jsonSerializerSettings);
Assert.AreEqual(someValue, deserializedObject[contextKey]);
+3 -2
View File
@@ -28,6 +28,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.IO;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Linq;
@@ -356,7 +357,7 @@ namespace Newtonsoft.Json.Bson
{
case State.ObjectStart:
{
SetToken(JsonToken.PropertyName, "$ref");
SetToken(JsonToken.PropertyName, JsonTypeReflector.RefPropertyName);
_bsonReaderState = BsonReaderState.ReferenceRef;
return true;
}
@@ -381,7 +382,7 @@ namespace Newtonsoft.Json.Bson
{
if (_bsonReaderState == BsonReaderState.ReferenceRef)
{
SetToken(JsonToken.PropertyName, "$id");
SetToken(JsonToken.PropertyName, JsonTypeReflector.IdPropertyName);
_bsonReaderState = BsonReaderState.ReferenceId;
return true;
}
+42 -22
View File
@@ -27,6 +27,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
@@ -420,7 +421,7 @@ namespace Newtonsoft.Json
if (t == JsonToken.Date)
{
if (Value is DateTime)
SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value));
SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value), false);
return (DateTimeOffset)Value;
}
@@ -438,15 +439,21 @@ namespace Newtonsoft.Json
return null;
}
if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
object temp;
if (DateTimeUtils.TryParseDateTime(s, DateParseHandling.DateTimeOffset, DateTimeZoneHandling, out temp))
{
SetToken(JsonToken.Date, dt);
dt = (DateTimeOffset)temp;
SetToken(JsonToken.Date, dt, false);
return dt;
}
else
if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
{
throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
SetToken(JsonToken.Date, dt, false);
return dt;
}
throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
}
if (t == JsonToken.EndArray)
@@ -479,7 +486,7 @@ namespace Newtonsoft.Json
{
byte[] data = ReadAsBytes();
ReadInternal();
SetToken(JsonToken.Bytes, data);
SetToken(JsonToken.Bytes, data, false);
return data;
}
@@ -488,7 +495,7 @@ namespace Newtonsoft.Json
{
string s = (string)Value;
byte[] data = (s.Length == 0) ? new byte[0] : Convert.FromBase64String(s);
SetToken(JsonToken.Bytes, data);
SetToken(JsonToken.Bytes, data, false);
return data;
}
@@ -512,7 +519,7 @@ namespace Newtonsoft.Json
break;
case JsonToken.EndArray:
byte[] d = data.ToArray();
SetToken(JsonToken.Bytes, d);
SetToken(JsonToken.Bytes, d, false);
return d;
case JsonToken.Comment:
// skip
@@ -553,7 +560,7 @@ namespace Newtonsoft.Json
if (t == JsonToken.Integer || t == JsonToken.Float)
{
if (!(Value is decimal))
SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture), false);
return (decimal)Value;
}
@@ -573,7 +580,7 @@ namespace Newtonsoft.Json
if (decimal.TryParse(s, NumberStyles.Number, Culture, out d))
{
SetToken(JsonToken.Float, d);
SetToken(JsonToken.Float, d, false);
return d;
}
else
@@ -610,7 +617,7 @@ namespace Newtonsoft.Json
if (t == JsonToken.Integer || t == JsonToken.Float)
{
if (!(Value is int))
SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture));
SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture), false);
return (int)Value;
}
@@ -630,7 +637,7 @@ namespace Newtonsoft.Json
if (int.TryParse(s, NumberStyles.Integer, Culture, out i))
{
SetToken(JsonToken.Integer, i);
SetToken(JsonToken.Integer, i, false);
return i;
}
else
@@ -680,7 +687,7 @@ namespace Newtonsoft.Json
else
s = Value.ToString();
SetToken(JsonToken.String, s);
SetToken(JsonToken.String, s, false);
return s;
}
}
@@ -720,16 +727,23 @@ namespace Newtonsoft.Json
return null;
}
object temp;
if (DateTimeUtils.TryParseDateTime(s, DateParseHandling.DateTime, DateTimeZoneHandling, out temp))
{
dt = (DateTime)temp;
dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
SetToken(JsonToken.Date, dt, false);
return dt;
}
if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
{
dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
SetToken(JsonToken.Date, dt);
SetToken(JsonToken.Date, dt, false);
return dt;
}
else
{
throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
}
throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
}
if (TokenType == JsonToken.EndArray)
@@ -747,13 +761,13 @@ namespace Newtonsoft.Json
if (!ReadInternal())
throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
if (Value.ToString() == "$type")
if (Value.ToString() == JsonTypeReflector.TypePropertyName)
{
ReadInternal();
if (Value != null && Value.ToString().StartsWith("System.Byte[]"))
{
ReadInternal();
if (Value.ToString() == "$value")
if (Value.ToString() == JsonTypeReflector.ValuePropertyName)
{
return true;
}
@@ -790,7 +804,7 @@ namespace Newtonsoft.Json
/// <param name="newToken">The new token.</param>
protected void SetToken(JsonToken newToken)
{
SetToken(newToken, null);
SetToken(newToken, null, true);
}
/// <summary>
@@ -799,6 +813,11 @@ namespace Newtonsoft.Json
/// <param name="newToken">The new token.</param>
/// <param name="value">The value.</param>
protected void SetToken(JsonToken newToken, object value)
{
SetToken(newToken, value, true);
}
internal void SetToken(JsonToken newToken, object value, bool updateIndex)
{
_tokenType = newToken;
_value = value;
@@ -845,7 +864,8 @@ namespace Newtonsoft.Json
else
SetFinished();
UpdateScopeWithFinishedValue();
if (updateIndex)
UpdateScopeWithFinishedValue();
break;
}
}
+20
View File
@@ -53,6 +53,7 @@ namespace Newtonsoft.Json
internal NullValueHandling _nullValueHandling;
internal DefaultValueHandling _defaultValueHandling;
internal ConstructorHandling _constructorHandling;
internal SpecialPropertyHandling _specialPropertyHandling;
internal JsonConverterCollection _converters;
internal IContractResolver _contractResolver;
internal ITraceWriter _traceWriter;
@@ -257,6 +258,22 @@ namespace Newtonsoft.Json
}
}
/// <summary>
/// Gets or sets how special properties are used during deserialization.
/// </summary>
/// <value>The special properties handling.</value>
public virtual SpecialPropertyHandling SpecialPropertyHandling
{
get { return _specialPropertyHandling; }
set
{
if (value < SpecialPropertyHandling.Default || value > SpecialPropertyHandling.ReadAhead)
throw new ArgumentOutOfRangeException("value");
_specialPropertyHandling = value;
}
}
/// <summary>
/// Gets a collection <see cref="JsonConverter"/> that will be used during serialization.
/// </summary>
@@ -426,6 +443,7 @@ namespace Newtonsoft.Json
_preserveReferencesHandling = JsonSerializerSettings.DefaultPreserveReferencesHandling;
_constructorHandling = JsonSerializerSettings.DefaultConstructorHandling;
_typeNameHandling = JsonSerializerSettings.DefaultTypeNameHandling;
_specialPropertyHandling = JsonSerializerSettings.DefaultSpecialPropertyHandling;
_context = JsonSerializerSettings.DefaultContext;
_binder = DefaultSerializationBinder.Instance;
@@ -515,6 +533,8 @@ namespace Newtonsoft.Json
// serializer specific
if (settings._typeNameHandling != null)
serializer.TypeNameHandling = settings.TypeNameHandling;
if (settings._specialPropertyHandling != null)
serializer.SpecialPropertyHandling = settings.SpecialPropertyHandling;
if (settings._typeNameAssemblyFormat != null)
serializer.TypeNameAssemblyFormat = settings.TypeNameAssemblyFormat;
if (settings._preserveReferencesHandling != null)
@@ -45,6 +45,7 @@ namespace Newtonsoft.Json
internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;
internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;
internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;
internal const SpecialPropertyHandling DefaultSpecialPropertyHandling = SpecialPropertyHandling.Default;
internal const FormatterAssemblyStyle DefaultTypeNameAssemblyFormat = FormatterAssemblyStyle.Simple;
internal static readonly StreamingContext DefaultContext;
@@ -83,6 +84,7 @@ namespace Newtonsoft.Json
internal StreamingContext? _context;
internal ConstructorHandling? _constructorHandling;
internal TypeNameHandling? _typeNameHandling;
internal SpecialPropertyHandling? _specialPropertyHandling;
/// <summary>
/// Gets or sets how reference loops (e.g. a class referencing itself) is handled.
@@ -160,6 +162,16 @@ namespace Newtonsoft.Json
set { _typeNameHandling = value; }
}
/// <summary>
/// Gets or sets how special properties are used during deserialization.
/// </summary>
/// <value>The special properties handling.</value>
public SpecialPropertyHandling SpecialPropertyHandling
{
get { return _specialPropertyHandling ?? DefaultSpecialPropertyHandling; }
set { _specialPropertyHandling = value; }
}
/// <summary>
/// Gets or sets how a type name assembly is written and resolved by the serializer.
/// </summary>
+1 -1
View File
@@ -687,7 +687,7 @@ namespace Newtonsoft.Json.Linq
break;
case JsonToken.StartConstructor:
JConstructor constructor = new JConstructor(r.Value.ToString());
constructor.SetLineInfo(constructor);
constructor.SetLineInfo(lineInfo);
parent.Add(constructor);
parent = constructor;
break;
+4
View File
@@ -130,6 +130,10 @@ namespace Newtonsoft.Json.Linq
internal override void InsertItem(int index, JToken item, bool skipParentCheck)
{
// don't add comments to JProperty
if (item != null && item.Type == JTokenType.Comment)
return;
if (Value != null)
throw new JsonException("{0} cannot have multiple values.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
+6 -2
View File
@@ -190,7 +190,11 @@ namespace Newtonsoft.Json.Linq
for (int i = 0; i < ancestors.Count; i++)
{
JToken current = ancestors[i];
JToken next = (i + 1 < ancestors.Count) ? ancestors[i + 1] : null;
JToken next = null;
if (i + 1 < ancestors.Count)
next = ancestors[i + 1];
else if (ancestors[i].Type == JTokenType.Property)
next = ancestors[i];
if (next != null)
{
@@ -1636,7 +1640,7 @@ namespace Newtonsoft.Json.Linq
/// <returns>An <see cref="JsonReader"/> that can be used to read this token and its descendants.</returns>
public JsonReader CreateReader()
{
return new JTokenReader(this);
return new JTokenReader(this, Path);
}
internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerializer)
+34 -2
View File
@@ -33,9 +33,10 @@ namespace Newtonsoft.Json.Linq
/// </summary>
public class JTokenReader : JsonReader, IJsonLineInfo
{
private readonly string _initialPath;
private readonly JToken _root;
private JToken _parent;
private JToken _current;
internal JToken _current;
/// <summary>
/// Initializes a new instance of the <see cref="JTokenReader"/> class.
@@ -49,6 +50,12 @@ namespace Newtonsoft.Json.Linq
_current = token;
}
internal JTokenReader(JToken token, string initialPath)
: this(token)
{
_initialPath = initialPath;
}
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
/// </summary>
@@ -227,7 +234,7 @@ namespace Newtonsoft.Json.Linq
SetToken(JsonToken.StartArray);
break;
case JTokenType.Constructor:
SetToken(JsonToken.StartConstructor);
SetToken(JsonToken.StartConstructor, ((JConstructor)token).Name);
break;
case JTokenType.Property:
SetToken(JsonToken.PropertyName, ((JProperty)token).Name);
@@ -319,5 +326,30 @@ namespace Newtonsoft.Json.Linq
return 0;
}
}
/// <summary>
/// Gets the path of the current JSON token.
/// </summary>
public override string Path
{
get
{
string path = base.Path;
if (!string.IsNullOrEmpty(_initialPath))
{
if (string.IsNullOrEmpty(path))
return _initialPath;
if (_initialPath.EndsWith("]", StringComparison.OrdinalIgnoreCase)
|| path.StartsWith("[", StringComparison.OrdinalIgnoreCase))
path = _initialPath + path;
else
path = _initialPath + "." + path;
}
return path;
}
}
}
}
@@ -126,6 +126,7 @@
<Compile Include="Serialization\MemoryTraceWriter.cs" />
<Compile Include="Serialization\TraceJsonReader.cs" />
<Compile Include="Serialization\TraceJsonWriter.cs" />
<Compile Include="SpecialPropertyHandling.cs" />
<Compile Include="StringEscapeHandling.cs" />
<Compile Include="Utilities\DateTimeParser.cs" />
<Compile Include="Utilities\DynamicProxy.cs" />
@@ -137,6 +137,7 @@
<Compile Include="Serialization\MemoryTraceWriter.cs" />
<Compile Include="Serialization\TraceJsonReader.cs" />
<Compile Include="Serialization\TraceJsonWriter.cs" />
<Compile Include="SpecialPropertyHandling.cs" />
<Compile Include="StringEscapeHandling.cs" />
<Compile Include="TraceLevel.cs" />
<Compile Include="Utilities\DateTimeParser.cs" />
@@ -137,6 +137,7 @@
<Compile Include="Serialization\MemoryTraceWriter.cs" />
<Compile Include="Serialization\TraceJsonReader.cs" />
<Compile Include="Serialization\TraceJsonWriter.cs" />
<Compile Include="SpecialPropertyHandling.cs" />
<Compile Include="StringEscapeHandling.cs" />
<Compile Include="Utilities\DateTimeParser.cs" />
<Compile Include="Utilities\DynamicProxy.cs" />
@@ -192,6 +192,7 @@
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="Serialization\TraceJsonReader.cs" />
<Compile Include="Serialization\TraceJsonWriter.cs" />
<Compile Include="SpecialPropertyHandling.cs" />
<Compile Include="StringEscapeHandling.cs" />
<Compile Include="TraceLevel.cs" />
<Compile Include="TypeNameHandling.cs" />
@@ -197,6 +197,7 @@
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="Serialization\TraceJsonReader.cs" />
<Compile Include="Serialization\TraceJsonWriter.cs" />
<Compile Include="SpecialPropertyHandling.cs" />
<Compile Include="StringEscapeHandling.cs" />
<Compile Include="TraceLevel.cs" />
<Compile Include="TypeNameHandling.cs" />
@@ -136,6 +136,7 @@
<Compile Include="MissingMemberHandling.cs" />
<Compile Include="NullValueHandling.cs" />
<Compile Include="ObjectCreationHandling.cs" />
<Compile Include="SpecialPropertyHandling.cs" />
<Compile Include="PreserveReferencesHandling.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
@@ -91,5 +91,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.1.16929")]
[assembly: AssemblyFileVersion("6.0.1.17101")]
[assembly: CLSCompliant(true)]
@@ -25,6 +25,7 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
@@ -194,7 +195,7 @@ namespace Newtonsoft.Json.Schema
throw JsonException.Create(token, token.Path, "Expected object while parsing schema object, got {0}.".FormatWith(CultureInfo.InvariantCulture, token.Type));
JToken referenceToken;
if (schemaObject.TryGetValue(JsonSchemaConstants.ReferencePropertyName, out referenceToken))
if (schemaObject.TryGetValue(JsonTypeReflector.RefPropertyName, out referenceToken))
{
JsonSchema deferredSchema = new JsonSchema();
deferredSchema.DeferredReference = (string)referenceToken;
@@ -63,8 +63,6 @@ namespace Newtonsoft.Json.Schema
public const string OptionValuePropertyName = "value";
public const string OptionLabelPropertyName = "label";
public const string ReferencePropertyName = "$ref";
public static readonly IDictionary<string, JsonSchemaType> JsonSchemaTypeMapping = new Dictionary<string, JsonSchemaType>
{
{ "string", JsonSchemaType.String },
@@ -25,6 +25,7 @@
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
@@ -52,7 +53,7 @@ namespace Newtonsoft.Json.Schema
if (schema.Id != null && _resolver.GetSchema(schema.Id) != null)
{
_writer.WriteStartObject();
_writer.WritePropertyName(JsonSchemaConstants.ReferencePropertyName);
_writer.WritePropertyName(JsonTypeReflector.RefPropertyName);
_writer.WriteValue(schema.Id);
_writer.WriteEndObject();
}
@@ -227,20 +227,33 @@ namespace Newtonsoft.Json.Serialization
ValidationUtils.ArgumentNotNull(reader, "reader");
// this is needed because we've already read inside the object, looking for special properties
JToken token;
using (JTokenWriter writer = new JTokenWriter())
{
writer.WriteStartObject();
if (reader.TokenType == JsonToken.PropertyName)
writer.WriteToken(reader, reader.Depth - 1, true, true);
else
writer.WriteEndObject();
do
{
if (reader.TokenType == JsonToken.PropertyName)
{
string propertyName = (string)reader.Value;
if (!reader.Read())
break;
token = writer.Token;
if (CheckPropertyName(reader, propertyName))
continue;
writer.WritePropertyName(propertyName);
writer.WriteToken(reader, true, true);
}
else
{
writer.WriteEndObject();
return writer.Token;
}
} while (reader.Read());
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
}
return token;
}
private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
@@ -252,8 +265,8 @@ namespace Newtonsoft.Json.Serialization
{
switch (reader.TokenType)
{
// populate a typed object or generic dictionary/array
// depending upon whether an objectType was supplied
// populate a typed object or generic dictionary/array
// depending upon whether an objectType was supplied
case JsonToken.StartObject:
return CreateObject(reader, objectType, contract, member, containerContract, containerMember, existingValue);
case JsonToken.StartArray:
@@ -359,12 +372,32 @@ namespace Newtonsoft.Json.Serialization
private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
{
CheckedRead(reader);
string id;
object newValue;
if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
return newValue;
if (Serializer.SpecialPropertyHandling == SpecialPropertyHandling.ReadAhead)
{
var tokenReader = reader as JTokenReader;
if (tokenReader == null)
{
JToken t = JToken.ReadFrom(reader);
tokenReader = (JTokenReader)t.CreateReader();
// start
CheckedRead(tokenReader);
reader = tokenReader;
}
if (ReadSpecialPropertiesToken(tokenReader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
return newValue;
}
else
{
CheckedRead(reader);
if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
return newValue;
}
if (HasNoDefinedType(contract))
return CreateJObject(reader);
@@ -473,6 +506,90 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
".FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract)));
}
private bool ReadSpecialPropertiesToken(JTokenReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
{
id = null;
newValue = null;
if (reader.TokenType == JsonToken.StartObject)
{
JObject current = (JObject)reader._current;
JToken refToken = current[JsonTypeReflector.RefPropertyName];
if (refToken != null)
{
if (refToken.Type != JTokenType.String && refToken.Type != JTokenType.Null)
throw JsonSerializationException.Create(refToken, refToken.Path, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null);
JToken property = refToken.Parent;
JToken additionalContent = null;
if (property.Next != null)
additionalContent = property.Next;
else if (property.Previous != null)
additionalContent = property.Previous;
string reference = (string)refToken;
if (reference != null)
{
if (additionalContent != null)
throw JsonSerializationException.Create(additionalContent, additionalContent.Path, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null);
newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference);
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);
reader.Skip();
return true;
}
}
JToken typeToken = current[JsonTypeReflector.TypePropertyName];
if (typeToken != null)
{
string qualifiedTypeName = (string)typeToken;
JsonReader typeTokenReader = typeToken.CreateReader();
CheckedRead(typeTokenReader);
ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName);
JToken valueToken = current[JsonTypeReflector.ValuePropertyName];
if (valueToken != null)
{
while (true)
{
CheckedRead(reader);
if (reader.TokenType == JsonToken.PropertyName)
{
if ((string)reader.Value == JsonTypeReflector.ValuePropertyName)
return false;
}
CheckedRead(reader);
reader.Skip();
}
}
}
JToken idToken = current[JsonTypeReflector.IdPropertyName];
if (idToken != null)
{
id = (string)idToken;
}
JToken valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName];
if (valuesToken != null)
{
JsonReader listReader = valuesToken.CreateReader();
CheckedRead(listReader);
newValue = CreateList(listReader, objectType, contract, member, existingValue, id);
reader.Skip();
return true;
}
}
CheckedRead(reader);
return false;
}
private bool ReadSpecialProperties(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
{
id = null;
@@ -524,44 +641,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
CheckedRead(reader);
string qualifiedTypeName = reader.Value.ToString();
TypeNameHandling resolvedTypeNameHandling =
((member != null) ? member.TypeNameHandling : null)
?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null)
?? Serializer._typeNameHandling;
if (resolvedTypeNameHandling != TypeNameHandling.None)
{
string typeName;
string assemblyName;
ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);
Type specifiedType;
try
{
specifiedType = Serializer._binder.BindToType(assemblyName, typeName);
}
catch (Exception ex)
{
throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
}
if (specifiedType == null)
throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved type '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName, specifiedType)), null);
if (objectType != null
#if !(NET35 || NET20 || PORTABLE40)
&& objectType != typeof(IDynamicMetaObjectProvider)
#endif
&& !objectType.IsAssignableFrom(specifiedType))
throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
objectType = specifiedType;
contract = GetContractSafe(specifiedType);
}
ResolveTypeName(reader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName);
CheckedRead(reader);
@@ -595,6 +675,48 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
return false;
}
private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, string qualifiedTypeName)
{
TypeNameHandling resolvedTypeNameHandling =
((member != null) ? member.TypeNameHandling : null)
?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null)
?? Serializer._typeNameHandling;
if (resolvedTypeNameHandling != TypeNameHandling.None)
{
string typeName;
string assemblyName;
ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);
Type specifiedType;
try
{
specifiedType = Serializer._binder.BindToType(assemblyName, typeName);
}
catch (Exception ex)
{
throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
}
if (specifiedType == null)
throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved type '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName, specifiedType)), null);
if (objectType != null
#if !(NET35 || NET20 || PORTABLE40)
&& objectType != typeof(IDynamicMetaObjectProvider)
#endif
&& !objectType.IsAssignableFrom(specifiedType))
throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
objectType = specifiedType;
contract = GetContractSafe(specifiedType);
}
}
private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
{
if (contract == null)
@@ -997,6 +1119,8 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
{
case JsonToken.PropertyName:
object keyValue = reader.Value;
if (CheckPropertyName(reader, keyValue.ToString()))
continue;
try
{
try
@@ -1751,6 +1875,9 @@ To fix this error either change the environment to be fully trusted, change the
{
string memberName = reader.Value.ToString();
if (CheckPropertyName(reader, memberName))
continue;
try
{
// attempt exact case match first
@@ -1793,8 +1920,8 @@ To fix this error either change the environment to be fully trusted, change the
else
throw;
}
}
break;
}
case JsonToken.EndObject:
finished = true;
break;
@@ -1815,6 +1942,23 @@ To fix this error either change the environment to be fully trusted, change the
return newObject;
}
private bool CheckPropertyName(JsonReader reader, string memberName)
{
if (Serializer.SpecialPropertyHandling == SpecialPropertyHandling.ReadAhead)
{
switch (memberName)
{
case JsonTypeReflector.IdPropertyName:
case JsonTypeReflector.RefPropertyName:
case JsonTypeReflector.TypePropertyName:
case JsonTypeReflector.ArrayValuesPropertyName:
reader.Skip();
return true;
}
}
return false;
}
private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o)
{
if (contract.ExtensionDataSetter != null)
@@ -108,6 +108,12 @@ namespace Newtonsoft.Json.Serialization
set { _serializer.TypeNameHandling = value; }
}
public override SpecialPropertyHandling SpecialPropertyHandling
{
get { return _serializer.SpecialPropertyHandling; }
set { _serializer.SpecialPropertyHandling = value; }
}
public override FormatterAssemblyStyle TypeNameAssemblyFormat
{
get { return _serializer.TypeNameAssemblyFormat; }
@@ -0,0 +1,47 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Text;
namespace Newtonsoft.Json
{
/// <summary>
/// Specifies special property handling options for the <see cref="JsonSerializer"/>.
/// </summary>
public enum SpecialPropertyHandling
{
/// <summary>
/// Read special properties located at the start of a JSON object.
/// </summary>
Default = 0,
/// <summary>
/// Read special properties located anywhere in a JSON object. Note that this setting will impact performance.
/// </summary>
ReadAhead = 1,
}
}