Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorJamesNK <james@newtonking.com>2010-07-03 13:53:57 +0400
committerJamesNK <james@newtonking.com>2010-07-03 13:53:57 +0400
commitc2800930ab4a66710c56d5aa6c3fb32269af0446 (patch)
tree1942e2b998c3e4be0c7dc55254a333e324f0e007 /Src
parentc9ec2289421792fc28a6a37e700e8da633a3fe92 (diff)
-Added DateTimeKindHandling to BsonWriter to control how a DateTime is converted prior to being serialized
-Added Required.Always attribute validation when writing JSON as well reading -Added TypeNameHandling.Auto to automatically write the type name when a value doesn't match the declared type -Fixed reading multi-byte strings in BSON
Diffstat (limited to 'Src')
-rw-r--r--Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs40
-rw-r--r--Src/Newtonsoft.Json.Tests/PerformanceTests.cs8
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs20
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs132
-rw-r--r--Src/Newtonsoft.Json.Tests/TestObjects/HolderClass.cs2
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs11
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonReader.cs14
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonWriter.cs11
-rw-r--r--Src/Newtonsoft.Json/JsonConvert.cs9
-rw-r--r--Src/Newtonsoft.Json/JsonSerializer.cs2
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs99
-rw-r--r--Src/Newtonsoft.Json/TypeNameHandling.cs4
12 files changed, 249 insertions, 103 deletions
diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs
index ca64132..b90e74a 100644
--- a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs
@@ -558,5 +558,45 @@ namespace Newtonsoft.Json.Tests.Bson
Assert.IsFalse(reader.Read());
}
+
+ [Test]
+ public void WriteDateTimes()
+ {
+ MemoryStream ms = new MemoryStream();
+ BsonWriter writer = new BsonWriter(ms);
+ writer.DateTimeKindHandling = DateTimeKind.Unspecified;
+
+ writer.WriteStartArray();
+ writer.WriteValue(new DateTime(2000, 10, 12, 20, 55, 0, DateTimeKind.Utc));
+ writer.WriteValue(new DateTime(2000, 10, 12, 20, 55, 0, DateTimeKind.Local));
+ writer.WriteValue(new DateTime(2000, 10, 12, 20, 55, 0, DateTimeKind.Unspecified));
+ writer.WriteEndArray();
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ BsonReader reader = new BsonReader(ms);
+ reader.ReadRootValueAsArray = true;
+ reader.DateTimeKindHandling = DateTimeKind.Utc;
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Date, reader.TokenType);
+ Assert.AreEqual(new DateTime(2000, 10, 12, 20, 55, 0, DateTimeKind.Utc), reader.Value);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Date, reader.TokenType);
+ Assert.AreEqual(new DateTime(2000, 10, 12, 20, 55, 0, DateTimeKind.Utc), reader.Value);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.Date, reader.TokenType);
+ Assert.AreEqual(new DateTime(2000, 10, 12, 20, 55, 0, DateTimeKind.Utc), reader.Value);
+
+ Assert.IsTrue(reader.Read());
+ Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
+
+ Assert.IsFalse(reader.Read());
+ }
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
index 4555ec7..d31ab1d 100644
--- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
+++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
@@ -34,8 +34,8 @@ namespace Newtonsoft.Json.Tests
public class PerformanceTests : TestFixtureBase
{
- //private const int Iterations = 100;
- private const int Iterations = 5000;
+ private const int Iterations = 100;
+ //private const int Iterations = 5000;
#region Data
private const string BsonHex =
@@ -508,7 +508,7 @@ namespace Newtonsoft.Json.Tests
TimeOperation<object>(() =>
{
- for (int i = 0; i < 5000; i++)
+ for (int i = 0; i < Iterations; i++)
{
test["dummy"] = new JValue(i);
Encoding.UTF8.GetBytes(test.ToString(Formatting.None));
@@ -526,7 +526,7 @@ namespace Newtonsoft.Json.Tests
TimeOperation<object>(() =>
{
- for (int i = 0; i < 5000; i++)
+ for (int i = 0; i < Iterations; i++)
{
test["dummy"] = new JValue(i);
ms.Seek(0, SeekOrigin.Begin);
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
index 91d6067..5c5a84f 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
@@ -1012,7 +1012,7 @@ keyword such as type of business.""
}
[Test]
- public void RequiredMembersClassWithNullValues()
+ public void DeserializeRequiredMembersClassWithNullValues()
{
string json = @"{
""FirstName"": ""I can't be null bro!"",
@@ -1030,7 +1030,7 @@ keyword such as type of business.""
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Required property 'FirstName' expects a value but got null.")]
- public void RequiredMembersClassNullRequiredValueProperty()
+ public void DeserializeRequiredMembersClassNullRequiredValueProperty()
{
string json = @"{
""FirstName"": null,
@@ -1043,6 +1043,22 @@ keyword such as type of business.""
}
[Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Cannot write a null value for property 'FirstName'. Property requires a value.")]
+ public void SerializeRequiredMembersClassNullRequiredValueProperty()
+ {
+ RequiredMembersClass requiredMembersClass = new RequiredMembersClass
+ {
+ FirstName = null,
+ BirthDate = new DateTime(2000, 10, 10, 10, 10, 10, DateTimeKind.Utc),
+ LastName = null,
+ MiddleName = null
+ };
+
+ string json = JsonConvert.SerializeObject(requiredMembersClass);
+ Console.WriteLine(json);
+ }
+
+ [Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Required property 'LastName' not found in JSON.")]
public void RequiredMembersClassMissingRequiredProperty()
{
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
index 382e0d2..06b0315 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
@@ -461,60 +461,82 @@ namespace Newtonsoft.Json.Tests.Serialization
}
#endif
- //[Test]
- //[Ignore("TODO")]
- //public void CollectionWithAbstractItems()
- //{
- // string Text = "";
-
- // HolderClass testObject = new HolderClass();
- // testObject.TestMember = new ContentSubClass("First One");
- // testObject.AnotherTestMember = new Dictionary<int, List<ContentBaseClass>>();
- // testObject.AnotherTestMember.Add(1, new List<ContentBaseClass>());
- // testObject.AnotherTestMember[1].Add(new ContentSubClass("Second One"));
- // testObject.AThirdTestMember = new ContentSubClass("Third One");
-
- // HolderClass anotherTestObject = null;
-
- // Newtonsoft.Json.JsonSerializer serializingTester = new Newtonsoft.Json.JsonSerializer();
- // serializingTester.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
-
- // StringWriter sw = new StringWriter();
- // using (Newtonsoft.Json.JsonTextWriter jsonWriter = new Newtonsoft.Json.JsonTextWriter(sw))
- // {
- // jsonWriter.Formatting = Newtonsoft.Json.Formatting.Indented;
-
- // if (Text.Equals("Properties All, Serializer All"))
- // serializingTester.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All;
- // else if (Text.Equals("Properties All, Serializer Objects"))
- // serializingTester.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;
- // else if (Text.Equals("Properties All, Serializer Arrays"))
- // serializingTester.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Arrays;
- // //otherwise leave default, which looks like it's "None"
-
- // serializingTester.Serialize(jsonWriter, testObject);
- // }
-
- // string json = sw.ToString();
-
- // Console.WriteLine(json);
-
- // StringReader sr = new StringReader(json);
-
- // Newtonsoft.Json.JsonSerializer deserializingTester = new Newtonsoft.Json.JsonSerializer();
-
- // using (Newtonsoft.Json.JsonTextReader jsonReader = new Newtonsoft.Json.JsonTextReader(sr))
- // {
- // if (Text.Equals("Properties All, Serializer All"))
- // deserializingTester.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All;
- // else if (Text.Equals("Properties All, Serializer Objects"))
- // deserializingTester.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;
- // else if (Text.Equals("Properties All, Serializer Arrays"))
- // deserializingTester.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Arrays;
- // //otherwise leave default, which looks like it's "None"
-
- // anotherTestObject = deserializingTester.Deserialize<HolderClass>(jsonReader);
- // }
- //}
+ [Test]
+ public void CollectionWithAbstractItems()
+ {
+ HolderClass testObject = new HolderClass();
+ testObject.TestMember = new ContentSubClass("First One");
+ testObject.AnotherTestMember = new Dictionary<int, IList<ContentBaseClass>>();
+ testObject.AnotherTestMember.Add(1, new List<ContentBaseClass>());
+ testObject.AnotherTestMember[1].Add(new ContentSubClass("Second One"));
+ testObject.AThirdTestMember = new ContentSubClass("Third One");
+
+
+ JsonSerializer serializingTester = new JsonSerializer();
+ serializingTester.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
+
+ StringWriter sw = new StringWriter();
+ using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
+ {
+ jsonWriter.Formatting = Formatting.Indented;
+ serializingTester.TypeNameHandling = TypeNameHandling.Auto;
+ serializingTester.Serialize(jsonWriter, testObject);
+ }
+
+ string json = sw.ToString();
+
+ string contentSubClassRef = ReflectionUtils.GetTypeName(typeof(ContentSubClass), FormatterAssemblyStyle.Simple);
+ string dictionaryRef = ReflectionUtils.GetTypeName(typeof(Dictionary<int, IList<ContentBaseClass>>), FormatterAssemblyStyle.Simple);
+ string listRef = ReflectionUtils.GetTypeName(typeof(List<ContentBaseClass>), FormatterAssemblyStyle.Simple);
+
+
+ Assert.AreEqual(@"{
+ ""TestMember"": {
+ ""$type"": """ + contentSubClassRef + @""",
+ ""SomeString"": ""First One""
+ },
+ ""AnotherTestMember"": {
+ ""$type"": """ + dictionaryRef + @""",
+ ""1"": {
+ ""$type"": """ + listRef + @""",
+ ""$values"": [
+ {
+ ""$type"": """ + contentSubClassRef + @""",
+ ""SomeString"": ""Second One""
+ }
+ ]
+ }
+ },
+ ""AThirdTestMember"": {
+ ""$type"": """ + contentSubClassRef + @""",
+ ""SomeString"": ""Third One""
+ }
+}", json);
+ Console.WriteLine(json);
+
+ StringReader sr = new StringReader(json);
+
+ JsonSerializer deserializingTester = new JsonSerializer();
+
+ HolderClass anotherTestObject;
+
+ using (JsonTextReader jsonReader = new JsonTextReader(sr))
+ {
+ deserializingTester.TypeNameHandling = TypeNameHandling.Auto;
+
+ anotherTestObject = deserializingTester.Deserialize<HolderClass>(jsonReader);
+ }
+
+ Assert.IsNotNull(anotherTestObject);
+ Assert.IsInstanceOfType(typeof(ContentSubClass), anotherTestObject.TestMember);
+ Assert.IsInstanceOfType(typeof(Dictionary<int, IList<ContentBaseClass>>), anotherTestObject.AnotherTestMember);
+ Assert.AreEqual(1, anotherTestObject.AnotherTestMember.Count);
+
+ IList<ContentBaseClass> list = anotherTestObject.AnotherTestMember[1];
+
+ Assert.IsInstanceOfType(typeof(List<ContentBaseClass>), list);
+ Assert.AreEqual(1, list.Count);
+ Assert.IsInstanceOfType(typeof(ContentSubClass), list[0]);
+ }
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/HolderClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/HolderClass.cs
index 27b26f4..14bcd5e 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/HolderClass.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/HolderClass.cs
@@ -13,7 +13,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
public ContentBaseClass TestMember { get; set; }
[Newtonsoft.Json.JsonProperty(TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All)]
- public Dictionary<int, List<ContentBaseClass>> AnotherTestMember { get; set; }
+ public Dictionary<int, IList<ContentBaseClass>> AnotherTestMember { get; set; }
public ContentBaseClass AThirdTestMember { get; set; }
diff --git a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
index a391e61..84a7ffb 100644
--- a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
+++ b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
@@ -17,8 +17,11 @@ namespace Newtonsoft.Json.Bson
private byte[] _largeByteBuffer;
private int _maxChars;
+ public DateTimeKind DateTimeKindHandling { get; set; }
+
public BsonBinaryWriter(Stream stream)
{
+ DateTimeKindHandling = DateTimeKind.Utc;
_writer = new BinaryWriter(stream);
}
@@ -107,8 +110,12 @@ namespace Newtonsoft.Json.Bson
if (value.Value is DateTime)
{
DateTime dateTime = (DateTime) value.Value;
- dateTime = dateTime.ToUniversalTime();
- ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime);
+ if (DateTimeKindHandling == DateTimeKind.Utc)
+ dateTime = dateTime.ToUniversalTime();
+ else if (DateTimeKindHandling == DateTimeKind.Local)
+ dateTime = dateTime.ToLocalTime();
+
+ ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime, false);
}
#if !PocketPC && !NET20
else
diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs
index 9f25b71..4b94357 100644
--- a/Src/Newtonsoft.Json/Bson/BsonReader.cs
+++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs
@@ -572,23 +572,27 @@ namespace Newtonsoft.Json.Bson
StringBuilder builder = null;
int totalBytesRead = 0;
+
+ // used in case of left over multibyte characters in the buffer
int offset = 0;
do
{
- // read up to the maximum size of the buffer or what is remaining, minus the offset
- // of left over multibyte chars
int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
? MaxCharBytesSize - offset
- : length - totalBytesRead - offset;
+ : length - totalBytesRead;
int byteCount = _reader.BaseStream.Read(_byteBuffer, offset, count);
if (byteCount == 0)
throw new EndOfStreamException("Unable to read beyond the end of the stream.");
+ totalBytesRead += byteCount;
+
+ // Above, byteCount is how many bytes we read this time.
+ // Below, byteCount is how many bytes are in the _byteBuffer.
byteCount += offset;
- if (totalBytesRead == 0 && byteCount == length)
+ if (byteCount == length)
{
// pref optimization to avoid reading into a string builder
// first iteration and all bytes read then return string directly
@@ -615,8 +619,6 @@ namespace Newtonsoft.Json.Bson
{
offset = 0;
}
-
- totalBytesRead += (byteCount - offset);
}
}
while (totalBytesRead < length);
diff --git a/Src/Newtonsoft.Json/Bson/BsonWriter.cs b/Src/Newtonsoft.Json/Bson/BsonWriter.cs
index 5382122..d3a380e 100644
--- a/Src/Newtonsoft.Json/Bson/BsonWriter.cs
+++ b/Src/Newtonsoft.Json/Bson/BsonWriter.cs
@@ -46,6 +46,17 @@ namespace Newtonsoft.Json.Bson
private string _propertyName;
/// <summary>
+ /// Gets or sets the <see cref="DateTimeKind" /> used when writing <see cref="DateTime"/> values to BSON.
+ /// When set to <see cref="DateTimeKind.Unspecified" /> no conversion will occur.
+ /// </summary>
+ /// <value>The <see cref="DateTimeKind" /> used when writing <see cref="DateTime"/> values to BSON.</value>
+ public DateTimeKind DateTimeKindHandling
+ {
+ get { return _writer.DateTimeKindHandling; }
+ set { _writer.DateTimeKindHandling = value; }
+ }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="BsonWriter"/> class.
/// </summary>
/// <param name="stream">The stream.</param>
diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs
index 40bdff4..c824cad 100644
--- a/Src/Newtonsoft.Json/JsonConvert.cs
+++ b/Src/Newtonsoft.Json/JsonConvert.cs
@@ -181,9 +181,14 @@ namespace Newtonsoft.Json
internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime)
{
- long universialTicks = ToUniversalTicks(dateTime);
+ return ConvertDateTimeToJavaScriptTicks(dateTime, true);
+ }
- return UniversialTicksToJavaScriptTicks(universialTicks);
+ internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, bool convertToUtc)
+ {
+ long ticks = (convertToUtc) ? ToUniversalTicks(dateTime) : dateTime.Ticks;
+
+ return UniversialTicksToJavaScriptTicks(ticks);
}
private static long UniversialTicksToJavaScriptTicks(long universialTicks)
diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs
index 655db63..e711c9f 100644
--- a/Src/Newtonsoft.Json/JsonSerializer.cs
+++ b/Src/Newtonsoft.Json/JsonSerializer.cs
@@ -109,7 +109,7 @@ namespace Newtonsoft.Json
get { return _typeNameHandling; }
set
{
- if (value < TypeNameHandling.None || value > TypeNameHandling.All)
+ if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
throw new ArgumentOutOfRangeException("value");
_typeNameHandling = value;
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
index ddb67db..33e364f 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
@@ -62,7 +62,7 @@ namespace Newtonsoft.Json.Serialization
if (jsonWriter == null)
throw new ArgumentNullException("jsonWriter");
- SerializeValue(jsonWriter, value, null, GetContractSafe(value));
+ SerializeValue(jsonWriter, value, GetContractSafe(value), null, null);
}
private JsonSerializerProxy GetInternalSerializer()
@@ -81,7 +81,7 @@ namespace Newtonsoft.Json.Serialization
return Serializer.ContractResolver.ResolveContract(value.GetType());
}
- private void SerializeValue(JsonWriter writer, object value, JsonProperty member, JsonContract contract)
+ private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContract collectionValueContract)
{
JsonConverter converter = (member != null) ? member.Converter : null;
@@ -92,39 +92,39 @@ namespace Newtonsoft.Json.Serialization
}
if ((converter != null
- || ((converter = contract.Converter) != null)
- || ((converter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
- || ((converter = contract.InternalConverter) != null))
+ || ((converter = valueContract.Converter) != null)
+ || ((converter = Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null)
+ || ((converter = valueContract.InternalConverter) != null))
&& converter.CanWrite)
{
- SerializeConvertable(writer, converter, value, contract);
+ SerializeConvertable(writer, converter, value, valueContract);
}
- else if (contract is JsonPrimitiveContract)
+ else if (valueContract is JsonPrimitiveContract)
{
writer.WriteValue(value);
}
- else if (contract is JsonStringContract)
+ else if (valueContract is JsonStringContract)
{
- SerializeString(writer, value, (JsonStringContract) contract);
+ SerializeString(writer, value, (JsonStringContract) valueContract);
}
- else if (contract is JsonObjectContract)
+ else if (valueContract is JsonObjectContract)
{
- SerializeObject(writer, value, (JsonObjectContract) contract, member);
+ SerializeObject(writer, value, (JsonObjectContract)valueContract, member, collectionValueContract);
}
- else if (contract is JsonDictionaryContract)
+ else if (valueContract is JsonDictionaryContract)
{
- JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
- SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member);
+ JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) valueContract;
+ SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, collectionValueContract);
}
- else if (contract is JsonArrayContract)
+ else if (valueContract is JsonArrayContract)
{
if (value is IList)
{
- SerializeList(writer, (IList) value, (JsonArrayContract) contract, member);
+ SerializeList(writer, (IList)value, (JsonArrayContract)valueContract, member, collectionValueContract);
}
else if (value is IEnumerable)
{
- SerializeList(writer, ((IEnumerable)value).Cast<object>().ToList(), (JsonArrayContract)contract, member);
+ SerializeList(writer, ((IEnumerable)value).Cast<object>().ToList(), (JsonArrayContract)valueContract, member, collectionValueContract);
}
else
{
@@ -133,14 +133,14 @@ namespace Newtonsoft.Json.Serialization
CultureInfo.InvariantCulture, value.GetType()));
}
}
- else if (contract is JsonLinqContract)
+ else if (valueContract is JsonLinqContract)
{
((JToken)value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
}
#if !SILVERLIGHT && !PocketPC
- else if (contract is JsonISerializableContract)
+ else if (valueContract is JsonISerializableContract)
{
- SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) contract);
+ SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) valueContract);
}
#endif
}
@@ -198,8 +198,11 @@ namespace Newtonsoft.Json.Serialization
if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling, contract))
return;
+ if (memberValue == null && property.Required == Required.Always)
+ throw new JsonSerializationException("Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
+
writer.WritePropertyName(propertyName);
- SerializeValue(writer, memberValue, property, contract);
+ SerializeValue(writer, memberValue, contract, property, null);
}
private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling, JsonContract contract)
@@ -286,7 +289,7 @@ namespace Newtonsoft.Json.Serialization
contract.InvokeOnSerialized(value, Serializer.Context);
}
- private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member)
+ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContract collectionValueContract)
{
contract.InvokeOnSerializing(value, Serializer.Context);
@@ -299,7 +302,7 @@ namespace Newtonsoft.Json.Serialization
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
writer.WriteValue(Serializer.ReferenceResolver.GetReference(value));
}
- if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, TypeNameHandling.Objects))
+ if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract))
{
WriteTypeProperty(writer, contract.UnderlyingType);
}
@@ -368,14 +371,14 @@ namespace Newtonsoft.Json.Serialization
}
}
- private void SerializeList(JsonWriter writer, IList values, JsonArrayContract contract, JsonProperty member)
+ private void SerializeList(JsonWriter writer, IList values, JsonArrayContract contract, JsonProperty member, JsonContract collectionValueContract)
{
contract.InvokeOnSerializing(values, Serializer.Context);
SerializeStack.Add(values);
bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
- bool includeTypeDetails = HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, TypeNameHandling.Arrays);
+ bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, collectionValueContract);
if (isReference || includeTypeDetails)
{
@@ -393,6 +396,8 @@ namespace Newtonsoft.Json.Serialization
writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName);
}
+ JsonContract childValuesContract = Serializer.ContractResolver.ResolveContract(contract.CollectionItemType ?? typeof(object));
+
writer.WriteStartArray();
int initialDepth = writer.Top;
@@ -413,7 +418,7 @@ namespace Newtonsoft.Json.Serialization
if (!CheckForCircularReference(value, null, contract))
continue;
- SerializeValue(writer, value, null, valueContract);
+ SerializeValue(writer, value, valueContract, null, childValuesContract);
}
}
catch (Exception ex)
@@ -451,7 +456,7 @@ namespace Newtonsoft.Json.Serialization
foreach (SerializationEntry serializationEntry in serializationInfo)
{
writer.WritePropertyName(serializationEntry.Name);
- SerializeValue(writer, serializationEntry.Value, null, GetContractSafe(serializationEntry.Value));
+ SerializeValue(writer, serializationEntry.Value, GetContractSafe(serializationEntry.Value), null, null);
}
writer.WriteEndObject();
@@ -461,7 +466,39 @@ namespace Newtonsoft.Json.Serialization
}
#endif
- private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member)
+ //private bool ShouldWriteTypeProperty(JsonProperty member, JsonContract contract, TypeNameHandling typeFlag)
+ //{
+ // if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, typeFlag))
+ // return true;
+
+ // if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) == TypeNameHandling.Auto)
+
+ // || (member != null
+ // && (member.TypeNameHandling ?? Serializer.TypeNameHandling) == TypeNameHandling.Auto
+ // && contract.UnderlyingType != member.PropertyType)
+ // )
+ //}
+
+ private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContract collectionValueContract)
+ {
+ if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, typeNameHandlingFlag))
+ return true;
+
+ if (member != null)
+ {
+ if ((member.TypeNameHandling ?? Serializer.TypeNameHandling) == TypeNameHandling.Auto && contract.UnderlyingType != member.PropertyType)
+ return true;
+ }
+ else if (collectionValueContract != null)
+ {
+ if (Serializer.TypeNameHandling == TypeNameHandling.Auto && contract.UnderlyingType != collectionValueContract.UnderlyingType)
+ return true;
+ }
+
+ return false;
+ }
+
+ private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContract collectionValueContract)
{
contract.InvokeOnSerializing(values.UnderlyingDictionary, Serializer.Context);
@@ -474,11 +511,13 @@ namespace Newtonsoft.Json.Serialization
writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
writer.WriteValue(Serializer.ReferenceResolver.GetReference(values.UnderlyingDictionary));
}
- if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, TypeNameHandling.Objects))
+ if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract))
{
WriteTypeProperty(writer, values.UnderlyingDictionary.GetType());
}
+ JsonContract childValuesContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object));
+
int initialDepth = writer.Top;
// Mono Unity 3.0 fix
@@ -505,7 +544,7 @@ namespace Newtonsoft.Json.Serialization
writer.WritePropertyName(propertyName);
- SerializeValue(writer, value, null, valueContract);
+ SerializeValue(writer, value, valueContract, null, childValuesContract);
}
}
catch (Exception ex)
diff --git a/Src/Newtonsoft.Json/TypeNameHandling.cs b/Src/Newtonsoft.Json/TypeNameHandling.cs
index d6ddd52..2a80c9c 100644
--- a/Src/Newtonsoft.Json/TypeNameHandling.cs
+++ b/Src/Newtonsoft.Json/TypeNameHandling.cs
@@ -24,6 +24,10 @@ namespace Newtonsoft.Json
/// </summary>
Arrays = 2,
/// <summary>
+ /// Include the .NET type name when the type of the object being serialized is not the same as its declared type.
+ /// </summary>
+ Auto = 4,
+ /// <summary>
/// Always include the .NET type name when serializing.
/// </summary>
All = Objects | Arrays