-Added DefaultValueHandling to JsonSerializer. Option to not write default values when serializing object
-Added JsonSerializerSettings and overloads to JavaScriptConvert.SerializeObject and JavaScriptConvert.DeserializeObject -Performance improvements
This commit is contained in:
@@ -39,6 +39,7 @@ using Newtonsoft.Json.Converters;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Globalization;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Newtonsoft.Json.Tests
|
||||
{
|
||||
@@ -1289,5 +1290,34 @@ keyword such as type of business.""
|
||||
string json = JavaScriptConvert.SerializeObject(new GenericImpl());
|
||||
Assert.AreEqual(@"{""Id"":0}", json);
|
||||
}
|
||||
|
||||
public class DefaultValueAttributeTestClass
|
||||
{
|
||||
[DefaultValue("TestProperty1Value")]
|
||||
public string TestProperty1 { get; set; }
|
||||
|
||||
[DefaultValue(21)]
|
||||
public int TestField1;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultValueAttributeTest()
|
||||
{
|
||||
string json = JavaScriptConvert.SerializeObject(new DefaultValueAttributeTestClass(),
|
||||
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
|
||||
Assert.AreEqual(@"{""TestField1"":0,""TestProperty1"":null}", json);
|
||||
|
||||
json = JavaScriptConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = int.MinValue, TestProperty1 = "NotDefault" },
|
||||
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
|
||||
Assert.AreEqual(@"{""TestField1"":-2147483648,""TestProperty1"":""NotDefault""}", json);
|
||||
|
||||
json = JavaScriptConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = 21, TestProperty1 = "NotDefault" },
|
||||
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
|
||||
Assert.AreEqual(@"{""TestProperty1"":""NotDefault""}", json);
|
||||
|
||||
json = JavaScriptConvert.SerializeObject(new DefaultValueAttributeTestClass { TestField1 = 21, TestProperty1 = "TestProperty1Value" },
|
||||
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
|
||||
Assert.AreEqual(@"{}", json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,7 @@
|
||||
<Compile Include="Linq\JTokenTests.cs" />
|
||||
<Compile Include="Linq\JValueTests.cs" />
|
||||
<Compile Include="Linq\LinqToJsonTest.cs" />
|
||||
<Compile Include="PerformanceTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SilverlightTests.cs" />
|
||||
<Compile Include="TestFixtureBase.cs" />
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
using System;
|
||||
#if !SILVERLIGHT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
|
||||
using System.Web.Script.Serialization;
|
||||
|
||||
using NUnit.Framework;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json.Tests
|
||||
{
|
||||
@@ -16,9 +20,16 @@ namespace Newtonsoft.Json.Tests
|
||||
/// </summary>
|
||||
public class PerformanceTests : TestFixtureBase
|
||||
{
|
||||
private DateTime BaseDate = DateTime.Parse("01/01/2000");
|
||||
private int Iterations = 100;
|
||||
|
||||
//JSONSerializer ser = null;
|
||||
public enum SerializeMethod
|
||||
{
|
||||
JsonNet,
|
||||
JavaScriptSerializer,
|
||||
DataContractJsonSerializer
|
||||
}
|
||||
|
||||
private DateTime BaseDate = DateTime.Parse("01/01/2000");
|
||||
|
||||
public string SerializeJsonNet(object value)
|
||||
{
|
||||
@@ -36,10 +47,7 @@ namespace Newtonsoft.Json.Tests
|
||||
StringWriter sw = new StringWriter();
|
||||
Newtonsoft.Json.JsonTextWriter writer = new JsonTextWriter(sw);
|
||||
|
||||
if (true)
|
||||
writer.Formatting = Formatting.Indented;
|
||||
else
|
||||
writer.Formatting = Formatting.None;
|
||||
writer.Formatting = Formatting.None;
|
||||
|
||||
writer.QuoteChar = '"';
|
||||
json.Serialize(writer, value);
|
||||
@@ -50,15 +58,120 @@ namespace Newtonsoft.Json.Tests
|
||||
return output;
|
||||
}
|
||||
|
||||
public object DeserializeJsonNet<T>(string json)
|
||||
{
|
||||
Type type = typeof(T);
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
|
||||
serializer.NullValueHandling = NullValueHandling.Ignore;
|
||||
|
||||
serializer.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace;
|
||||
serializer.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
|
||||
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
|
||||
return serializer.Deserialize(new StringReader(json), type);
|
||||
}
|
||||
|
||||
public string SerializeWebExtensions(object value)
|
||||
{
|
||||
JavaScriptSerializer ser = new JavaScriptSerializer();
|
||||
|
||||
List<JavaScriptConverter> converters = new List<JavaScriptConverter>();
|
||||
|
||||
return ser.Serialize(value);
|
||||
}
|
||||
|
||||
public object DeserializeWebExtensions<T>(string json)
|
||||
{
|
||||
JavaScriptSerializer ser = new JavaScriptSerializer();
|
||||
|
||||
return ser.Deserialize<T>(json);
|
||||
}
|
||||
|
||||
public string SerializeDataContract(object value)
|
||||
{
|
||||
DataContractJsonSerializer dataContractSerializer
|
||||
= new DataContractJsonSerializer(value.GetType());
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
dataContractSerializer.WriteObject(ms, value);
|
||||
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
using (StreamReader sr = new StreamReader(ms))
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public object DeserializeDataContract<T>(string json)
|
||||
{
|
||||
DataContractJsonSerializer dataContractSerializer
|
||||
= new DataContractJsonSerializer(typeof(T));
|
||||
|
||||
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
return dataContractSerializer.ReadObject(ms);
|
||||
}
|
||||
|
||||
public void BenchmarkSerializeMethod(SerializeMethod method, object value)
|
||||
{
|
||||
Stopwatch timed = new Stopwatch();
|
||||
timed.Start();
|
||||
|
||||
string json = null;
|
||||
for (int x = 0; x < Iterations; x++)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case SerializeMethod.JsonNet:
|
||||
json = JavaScriptConvert.SerializeObject(value);
|
||||
break;
|
||||
case SerializeMethod.JavaScriptSerializer:
|
||||
json = SerializeWebExtensions(value);
|
||||
break;
|
||||
case SerializeMethod.DataContractJsonSerializer:
|
||||
json = SerializeDataContract(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
timed.Stop();
|
||||
|
||||
Console.WriteLine("Serialize method: {0}", method);
|
||||
Console.WriteLine("{0} ms", timed.ElapsedMilliseconds);
|
||||
Console.WriteLine(json);
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public void BenchmarkDeserializeMethod<T>(SerializeMethod method, string json)
|
||||
{
|
||||
Stopwatch timed = new Stopwatch();
|
||||
timed.Start();
|
||||
|
||||
object value = null;
|
||||
for (int x = 0; x < Iterations; x++)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case SerializeMethod.JsonNet:
|
||||
value = DeserializeJsonNet<T>(json);
|
||||
break;
|
||||
case SerializeMethod.JavaScriptSerializer:
|
||||
value = DeserializeWebExtensions<T>(json);
|
||||
break;
|
||||
case SerializeMethod.DataContractJsonSerializer:
|
||||
value = DeserializeDataContract<T>(json);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
timed.Stop();
|
||||
|
||||
Console.WriteLine("Serialize method: {0}", method);
|
||||
Console.WriteLine("{0} ms", timed.ElapsedMilliseconds);
|
||||
Console.WriteLine(value);
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Serialize()
|
||||
@@ -83,19 +196,9 @@ namespace Newtonsoft.Json.Tests
|
||||
address.Address = "array 2 address";
|
||||
test.Addresses.Add(address);
|
||||
|
||||
Stopwatch timed = new Stopwatch();
|
||||
timed.Start();
|
||||
|
||||
string json = null;
|
||||
for (int x = 0; x < 10000; x++)
|
||||
{
|
||||
json = this.SerializeJsonNet(test);
|
||||
//json = this.SerializeWebExtensions(test);
|
||||
}
|
||||
timed.Stop();
|
||||
|
||||
Console.WriteLine("{0}", timed.ElapsedMilliseconds + " ms");
|
||||
Console.WriteLine("{0}", json);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNet, test);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JavaScriptSerializer, test);
|
||||
BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, test);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -134,19 +237,9 @@ namespace Newtonsoft.Json.Tests
|
||||
]
|
||||
}";
|
||||
|
||||
for (int x = 0; x < 10000; x++)
|
||||
{
|
||||
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
|
||||
|
||||
serializer.NullValueHandling = NullValueHandling.Ignore;
|
||||
|
||||
serializer.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace;
|
||||
serializer.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
|
||||
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
|
||||
TestClass test = (TestClass)serializer.Deserialize(new StringReader(json), typeof(TestClass));
|
||||
}
|
||||
|
||||
BenchmarkDeserializeMethod<TestClass>(SerializeMethod.JsonNet, json);
|
||||
BenchmarkDeserializeMethod<TestClass>(SerializeMethod.JavaScriptSerializer, json);
|
||||
BenchmarkDeserializeMethod<TestClass>(SerializeMethod.DataContractJsonSerializer, json);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,4 +322,5 @@ namespace Newtonsoft.Json.Tests
|
||||
private DateTime _Entered = DateTime.Parse("01/01/2007", CultureInfo.CurrentCulture.DateTimeFormat);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -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.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default value handling options for the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
public enum DefaultValueHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Include null values when serializing and deserializing objects.
|
||||
/// </summary>
|
||||
Include = 0,
|
||||
/// <summary>
|
||||
/// Ignore null values when serializing and deserializing objects.
|
||||
/// </summary>
|
||||
Ignore = 1
|
||||
}
|
||||
}
|
||||
@@ -430,7 +430,7 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A JSON string representation of the object.</returns>
|
||||
public static string SerializeObject(object value)
|
||||
{
|
||||
return SerializeObject(value, null);
|
||||
return SerializeObject(value, (JsonSerializerSettings)null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -441,17 +441,27 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A JSON string representation of the object.</returns>
|
||||
public static string SerializeObject(object value, params JsonConverter[] converters)
|
||||
{
|
||||
JsonSerializerSettings settings = (converters != null && converters.Length > 0)
|
||||
? new JsonSerializerSettings { Converters = converters }
|
||||
: null;
|
||||
|
||||
return SerializeObject(value, settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified object to a JSON string using a collection of <see cref="JsonConverter"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to serialize.</param>
|
||||
/// <param name="settings">
|
||||
/// The <see cref="JsonSerializerSettings"/> used to serialize the object.
|
||||
/// If this is null, default serialization settings will be is used.
|
||||
/// </param>
|
||||
/// <returns>A JSON string representation of the object.</returns>
|
||||
public static string SerializeObject(object value, JsonSerializerSettings settings)
|
||||
{
|
||||
JsonSerializer jsonSerializer = JsonSerializer.Create(settings);
|
||||
|
||||
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
|
||||
JsonSerializer jsonSerializer = new JsonSerializer();
|
||||
|
||||
if (!CollectionUtils.IsNullOrEmpty<JsonConverter>(converters))
|
||||
{
|
||||
for (int i = 0; i < converters.Length; i++)
|
||||
{
|
||||
jsonSerializer.Converters.Add(converters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
using (JsonWriter jsonWriter = new JsonTextWriter(sw))
|
||||
{
|
||||
//jsonWriter.Formatting = Formatting.Indented;
|
||||
@@ -468,7 +478,7 @@ namespace Newtonsoft.Json
|
||||
/// <returns>The deserialized object from the Json string.</returns>
|
||||
public static object DeserializeObject(string value)
|
||||
{
|
||||
return DeserializeObject(value, null, null);
|
||||
return DeserializeObject(value, null, (JsonSerializerSettings)null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -479,7 +489,7 @@ namespace Newtonsoft.Json
|
||||
/// <returns>The deserialized object from the Json string.</returns>
|
||||
public static object DeserializeObject(string value, Type type)
|
||||
{
|
||||
return DeserializeObject(value, type, null);
|
||||
return DeserializeObject(value, type, (JsonSerializerSettings)null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -530,16 +540,27 @@ namespace Newtonsoft.Json
|
||||
/// <returns>The deserialized object from the JSON string.</returns>
|
||||
public static object DeserializeObject(string value, Type type, params JsonConverter[] converters)
|
||||
{
|
||||
StringReader sr = new StringReader(value);
|
||||
JsonSerializer jsonSerializer = new JsonSerializer();
|
||||
JsonSerializerSettings settings = (converters != null && converters.Length > 0)
|
||||
? new JsonSerializerSettings { Converters = converters }
|
||||
: null;
|
||||
|
||||
if (!CollectionUtils.IsNullOrEmpty<JsonConverter>(converters))
|
||||
{
|
||||
for (int i = 0; i < converters.Length; i++)
|
||||
{
|
||||
jsonSerializer.Converters.Add(converters[i]);
|
||||
}
|
||||
}
|
||||
return DeserializeObject(value, type, settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the JSON string to the specified type.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to deserialize.</param>
|
||||
/// <param name="type">The type of the object to deserialize.</param>
|
||||
/// <param name="settings">
|
||||
/// The <see cref="JsonSerializerSettings"/> used to deserialize the object.
|
||||
/// If this is null, default serialization settings will be is used.
|
||||
/// </param>
|
||||
/// <returns>The deserialized object from the JSON string.</returns>
|
||||
public static object DeserializeObject(string value, Type type, JsonSerializerSettings settings)
|
||||
{
|
||||
StringReader sr = new StringReader(value);
|
||||
JsonSerializer jsonSerializer = JsonSerializer.Create(settings);
|
||||
|
||||
object deserializedValue;
|
||||
|
||||
|
||||
@@ -45,12 +45,13 @@ namespace Newtonsoft.Json
|
||||
public class JsonSerializer
|
||||
{
|
||||
private static readonly Dictionary<ICustomAttributeProvider, Type> ConverterTypeCache = new Dictionary<ICustomAttributeProvider, Type>();
|
||||
private static Dictionary<Type, MemberMappingCollection> TypeMemberMappings = new Dictionary<Type,MemberMappingCollection>();
|
||||
private static readonly Dictionary<Type, MemberMappingCollection> TypeMemberMappingsCache = new Dictionary<Type,MemberMappingCollection>();
|
||||
|
||||
private ReferenceLoopHandling _referenceLoopHandling;
|
||||
private MissingMemberHandling _missingMemberHandling;
|
||||
private ObjectCreationHandling _objectCreationHandling;
|
||||
private NullValueHandling _nullValueHandling;
|
||||
private DefaultValueHandling _defaultValueHandling;
|
||||
private int _level;
|
||||
private JsonConverterCollection _converters;
|
||||
|
||||
@@ -99,6 +100,21 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set how null default are handled during serialization and deserialization.
|
||||
/// </summary>
|
||||
public DefaultValueHandling DefaultValueHandling
|
||||
{
|
||||
get { return _defaultValueHandling; }
|
||||
set
|
||||
{
|
||||
if (value < DefaultValueHandling.Include || value > DefaultValueHandling.Ignore)
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
|
||||
_defaultValueHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how objects are created during deserialization.
|
||||
/// </summary>
|
||||
@@ -135,10 +151,31 @@ namespace Newtonsoft.Json
|
||||
/// </summary>
|
||||
public JsonSerializer()
|
||||
{
|
||||
_referenceLoopHandling = ReferenceLoopHandling.Error;
|
||||
_missingMemberHandling = MissingMemberHandling.Error;
|
||||
_nullValueHandling = NullValueHandling.Include;
|
||||
_objectCreationHandling = ObjectCreationHandling.Auto;
|
||||
_referenceLoopHandling = JsonSerializerSettings.DefaultReferenceLoopHandling;
|
||||
_missingMemberHandling = JsonSerializerSettings.DefaultMissingMemberHandling;
|
||||
_nullValueHandling = JsonSerializerSettings.DefaultNullValueHandling;
|
||||
_defaultValueHandling = JsonSerializerSettings.DefaultDefaultValueHandling;
|
||||
_objectCreationHandling = JsonSerializerSettings.DefaultObjectCreationHandling;
|
||||
}
|
||||
|
||||
|
||||
public static JsonSerializer Create(JsonSerializerSettings settings)
|
||||
{
|
||||
JsonSerializer jsonSerializer = new JsonSerializer();
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
if (!CollectionUtils.IsNullOrEmpty<JsonConverter>(settings.Converters))
|
||||
jsonSerializer.Converters.AddRange(settings.Converters);
|
||||
|
||||
jsonSerializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
|
||||
jsonSerializer.MissingMemberHandling = settings.MissingMemberHandling;
|
||||
jsonSerializer.ObjectCreationHandling = settings.ObjectCreationHandling;
|
||||
jsonSerializer.NullValueHandling = settings.NullValueHandling;
|
||||
jsonSerializer.DefaultValueHandling = settings.DefaultValueHandling;
|
||||
}
|
||||
|
||||
return jsonSerializer;
|
||||
}
|
||||
|
||||
#region Deserialize
|
||||
@@ -236,7 +273,7 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
value = CreateJToken(reader);
|
||||
}
|
||||
else if (typeof(IDictionary).IsAssignableFrom(objectType) || ReflectionUtils.IsSubClass(objectType, typeof(IDictionary<,>)))
|
||||
else if (typeof(IDictionary).IsAssignableFrom(objectType) || ReflectionUtils.ImplementsGenericInterfaceDefinition(objectType, typeof(IDictionary<,>)))
|
||||
{
|
||||
if (existingValue == null)
|
||||
value = CreateAndPopulateDictionary(reader, objectType);
|
||||
@@ -321,11 +358,11 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
MemberMappingCollection memberMappings;
|
||||
|
||||
if (TypeMemberMappings.TryGetValue(objectType, out memberMappings))
|
||||
if (TypeMemberMappingsCache.TryGetValue(objectType, out memberMappings))
|
||||
return memberMappings;
|
||||
|
||||
memberMappings = CreateMemberMappings(objectType);
|
||||
TypeMemberMappings[objectType] = memberMappings;
|
||||
TypeMemberMappingsCache[objectType] = memberMappings;
|
||||
|
||||
return memberMappings;
|
||||
}
|
||||
@@ -357,7 +394,10 @@ namespace Newtonsoft.Json
|
||||
|
||||
JsonConverter memberConverter = GetConverter(member, ReflectionUtils.GetMemberUnderlyingType(member));
|
||||
|
||||
MemberMapping memberMapping = new MemberMapping(mappedName, member, ignored, readable, writable, memberConverter);
|
||||
DefaultValueAttribute defaultValueAttribute = ReflectionUtils.GetAttribute<DefaultValueAttribute>(member, true);
|
||||
object defaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
|
||||
|
||||
MemberMapping memberMapping = new MemberMapping(mappedName, member, ignored, readable, writable, memberConverter, defaultValue);
|
||||
|
||||
memberMappings.AddMapping(memberMapping);
|
||||
}
|
||||
@@ -435,12 +475,18 @@ namespace Newtonsoft.Json
|
||||
|
||||
// get the member's underlying type
|
||||
memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
|
||||
object currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
|
||||
|
||||
bool useExistingValue = (currentValue != null
|
||||
&& (_objectCreationHandling == ObjectCreationHandling.Auto || _objectCreationHandling == ObjectCreationHandling.Reuse)
|
||||
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
|
||||
&& (!memberType.IsArray && !ReflectionUtils.IsSubClass(memberType, typeof(ReadOnlyCollection<>))));
|
||||
object currentValue = null;
|
||||
bool useExistingValue = false;
|
||||
|
||||
if ((_objectCreationHandling == ObjectCreationHandling.Auto || _objectCreationHandling == ObjectCreationHandling.Reuse)
|
||||
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject))
|
||||
{
|
||||
currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
|
||||
|
||||
useExistingValue = (currentValue != null && !memberType.IsArray && !ReflectionUtils.InheritsGenericClassDefinition(memberType, typeof(ReadOnlyCollection<>)));
|
||||
}
|
||||
|
||||
|
||||
if (!memberMapping.Writable && !useExistingValue)
|
||||
{
|
||||
@@ -453,6 +499,9 @@ namespace Newtonsoft.Json
|
||||
if (_nullValueHandling == NullValueHandling.Ignore && value == null)
|
||||
return;
|
||||
|
||||
if (_defaultValueHandling == DefaultValueHandling.Ignore && object.Equals(value, memberMapping.DefaultValue))
|
||||
return;
|
||||
|
||||
if (!useExistingValue)
|
||||
ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
|
||||
}
|
||||
@@ -712,8 +761,13 @@ namespace Newtonsoft.Json
|
||||
return false;
|
||||
}
|
||||
|
||||
private void WriteMemberInfoProperty(JsonWriter writer, object value, MemberInfo member, string propertyName, JsonConverter memberConverter)
|
||||
private void WriteMemberInfoProperty(JsonWriter writer, object value, MemberMapping memberMapping)
|
||||
{
|
||||
MemberInfo member = memberMapping.Member;
|
||||
string propertyName = memberMapping.MappingName;
|
||||
JsonConverter memberConverter = memberMapping.MemberConverter;
|
||||
object defaultValue = memberMapping.DefaultValue;
|
||||
|
||||
if (!ReflectionUtils.IsIndexedProperty(member))
|
||||
{
|
||||
object memberValue = ReflectionUtils.GetMemberValue(member, value);
|
||||
@@ -721,6 +775,9 @@ namespace Newtonsoft.Json
|
||||
if (_nullValueHandling == NullValueHandling.Ignore && memberValue == null)
|
||||
return;
|
||||
|
||||
if (_defaultValueHandling == DefaultValueHandling.Ignore && object.Equals(memberValue, defaultValue))
|
||||
return;
|
||||
|
||||
if (writer.SerializeStack.IndexOf(memberValue) != -1)
|
||||
{
|
||||
switch (_referenceLoopHandling)
|
||||
@@ -776,7 +833,7 @@ namespace Newtonsoft.Json
|
||||
foreach (MemberMapping memberMapping in memberMappings)
|
||||
{
|
||||
if (!memberMapping.Ignored && memberMapping.Readable)
|
||||
WriteMemberInfoProperty(writer, value, memberMapping.Member, memberMapping.MappingName, memberMapping.MemberConverter);
|
||||
WriteMemberInfoProperty(writer, value, memberMapping);
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
public class JsonSerializerSettings
|
||||
{
|
||||
internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;
|
||||
internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Error;
|
||||
internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;
|
||||
internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;
|
||||
internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;
|
||||
|
||||
public ReferenceLoopHandling ReferenceLoopHandling { get; set; }
|
||||
public MissingMemberHandling MissingMemberHandling { get; set; }
|
||||
public ObjectCreationHandling ObjectCreationHandling { get; set; }
|
||||
public NullValueHandling NullValueHandling { get; set; }
|
||||
public DefaultValueHandling DefaultValueHandling { get; set; }
|
||||
public IList<JsonConverter> Converters { get; set; }
|
||||
|
||||
public JsonSerializerSettings()
|
||||
{
|
||||
ReferenceLoopHandling = DefaultReferenceLoopHandling;
|
||||
MissingMemberHandling = DefaultMissingMemberHandling;
|
||||
ObjectCreationHandling = DefaultObjectCreationHandling;
|
||||
NullValueHandling = DefaultNullValueHandling;
|
||||
DefaultValueHandling = DefaultDefaultValueHandling;
|
||||
Converters = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,14 +207,13 @@ namespace Newtonsoft.Json
|
||||
if (Formatting == Formatting.Indented)
|
||||
{
|
||||
_writer.Write(Environment.NewLine);
|
||||
// for each level of object...
|
||||
for (int i = 0; i < Top; i++)
|
||||
|
||||
// levels of indentation multiplied by the indent count
|
||||
int currentIndentCount = Top * _indentation;
|
||||
|
||||
for (int i = 0; i < currentIndentCount; i++)
|
||||
{
|
||||
// ...write the indent char the specified number of times
|
||||
for (int j = 0; j < _indentation; j++)
|
||||
{
|
||||
_writer.Write(_indentChar);
|
||||
}
|
||||
_writer.Write(_indentChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,9 @@ namespace Newtonsoft.Json
|
||||
private readonly bool _readable;
|
||||
private readonly bool _writable;
|
||||
private readonly JsonConverter _memberConverter;
|
||||
private readonly object _defaultValue;
|
||||
|
||||
public MemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter)
|
||||
public MemberMapping(string mappingName, MemberInfo member, bool ignored, bool readable, bool writable, JsonConverter memberConverter, object defaultValue)
|
||||
{
|
||||
_mappingName = mappingName;
|
||||
_member = member;
|
||||
@@ -47,6 +48,7 @@ namespace Newtonsoft.Json
|
||||
_readable = readable;
|
||||
_writable = writable;
|
||||
_memberConverter = memberConverter;
|
||||
_defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public string MappingName
|
||||
@@ -77,6 +79,11 @@ namespace Newtonsoft.Json
|
||||
public JsonConverter MemberConverter
|
||||
{
|
||||
get { return _memberConverter; }
|
||||
}
|
||||
|
||||
public object DefaultValue
|
||||
{
|
||||
get { return _defaultValue; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,6 +218,7 @@
|
||||
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
|
||||
<Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
|
||||
<Compile Include="Converters\XmlNodeConverter.cs" />
|
||||
<Compile Include="DefaultValueHandling.cs" />
|
||||
<Compile Include="Identifier.cs" />
|
||||
<Compile Include="JavaScriptConvert.cs" />
|
||||
<Compile Include="JsonConverter.cs" />
|
||||
@@ -231,6 +232,7 @@
|
||||
<Compile Include="JsonReaderException.cs" />
|
||||
<Compile Include="JsonSerializationException.cs" />
|
||||
<Compile Include="JsonSerializer.cs" />
|
||||
<Compile Include="JsonSerializerSettings.cs" />
|
||||
<Compile Include="JsonTextReader.cs" />
|
||||
<Compile Include="JsonTextWriter.cs" />
|
||||
<Compile Include="JsonToken.cs" />
|
||||
@@ -260,6 +262,7 @@
|
||||
<Compile Include="ReferenceLoopHandling.cs" />
|
||||
<Compile Include="StringBuffer.cs" />
|
||||
<Compile Include="Utilities\CollectionUtils.cs" />
|
||||
<Compile Include="Utilities\CollectionWrapper.cs" />
|
||||
<Compile Include="Utilities\ConvertUtils.cs" />
|
||||
<Compile Include="Utilities\DateTimeUtils.cs" />
|
||||
<Compile Include="Utilities\DictionaryWrapper.cs" />
|
||||
|
||||
@@ -74,8 +74,10 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DefaultValueHandling.cs" />
|
||||
<Compile Include="JsonConverterAttribute.cs" />
|
||||
<Compile Include="JsonObjectAttribute.cs" />
|
||||
<Compile Include="JsonSerializerSettings.cs" />
|
||||
<Compile Include="Linq\IJEnumerable.cs" />
|
||||
<Compile Include="Linq\JTokenEqualityComparer.cs" />
|
||||
<Compile Include="MemberSerialization.cs" />
|
||||
|
||||
@@ -360,7 +360,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
return true;
|
||||
else if (typeof(IList).IsAssignableFrom(type))
|
||||
return true;
|
||||
else if (ReflectionUtils.IsSubClass(type, typeof(IList<>)))
|
||||
else if (ReflectionUtils.ImplementsGenericInterfaceDefinition(type, typeof(IList<>)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@@ -371,7 +371,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
ValidationUtils.ArgumentNotNull(list, "list");
|
||||
|
||||
Type collectionDefinition;
|
||||
if (ReflectionUtils.IsSubClass(list.GetType(), typeof(ICollection<>), out collectionDefinition))
|
||||
if (ReflectionUtils.ImplementsGenericInterfaceDefinition(list.GetType(), typeof(ICollection<>), out collectionDefinition))
|
||||
{
|
||||
Type collectionItemType = ReflectionUtils.GetCollectionItemType(collectionDefinition);
|
||||
|
||||
@@ -398,7 +398,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
ValidationUtils.ArgumentNotNull(list, "list");
|
||||
|
||||
Type listDefinition;
|
||||
if (ReflectionUtils.IsSubClass(list.GetType(), typeof(IList<>), out listDefinition))
|
||||
if (ReflectionUtils.ImplementsGenericInterfaceDefinition(list.GetType(), typeof(IList<>), out listDefinition))
|
||||
{
|
||||
Type collectionItemType = ReflectionUtils.GetCollectionItemType(listDefinition);
|
||||
|
||||
@@ -426,7 +426,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
|
||||
|
||||
Type dictionaryDefinition;
|
||||
if (ReflectionUtils.IsSubClass(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
|
||||
if (ReflectionUtils.ImplementsGenericInterfaceDefinition(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
|
||||
{
|
||||
Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryDefinition);
|
||||
Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryDefinition);
|
||||
@@ -466,7 +466,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
list = new List<object>();
|
||||
isReadOnlyOrFixedSize = true;
|
||||
}
|
||||
else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>), out collectionType))
|
||||
else if (ReflectionUtils.InheritsGenericClassDefinition(listType, typeof(ReadOnlyCollection<>), out collectionType))
|
||||
{
|
||||
Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
|
||||
Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
|
||||
@@ -522,7 +522,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
if (listType.IsArray)
|
||||
list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(listType));
|
||||
else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>)))
|
||||
else if (ReflectionUtils.InheritsGenericClassDefinition(listType, typeof(ReadOnlyCollection<>)))
|
||||
list = (IList)Activator.CreateInstance(listType, list);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,47 +124,77 @@ namespace Newtonsoft.Json.Utilities
|
||||
return !CollectionUtils.IsNullOrEmpty<ParameterInfo>(property.GetIndexParameters());
|
||||
}
|
||||
|
||||
public static bool IsSubClass(Type type, Type check)
|
||||
public static bool ImplementsGenericInterfaceDefinition(Type type, Type genericInterfaceDefinition)
|
||||
{
|
||||
Type implementingType;
|
||||
return IsSubClass(type, check, out implementingType);
|
||||
return ImplementsGenericInterfaceDefinition(type, genericInterfaceDefinition, out implementingType);
|
||||
}
|
||||
|
||||
public static bool IsSubClass(Type type, Type check, out Type implementingType)
|
||||
public static bool ImplementsGenericInterfaceDefinition(Type type, Type genericInterfaceDefinition, out Type implementingType)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(type, "type");
|
||||
ValidationUtils.ArgumentNotNull(check, "check");
|
||||
ValidationUtils.ArgumentNotNull(genericInterfaceDefinition, "genericInterfaceDefinition");
|
||||
|
||||
return IsSubClassInternal(type, type, check, out implementingType);
|
||||
}
|
||||
if (!genericInterfaceDefinition.IsInterface || !genericInterfaceDefinition.IsGenericTypeDefinition)
|
||||
throw new ArgumentNullException("'{0}' is not a generic interface definition.".FormatWith(CultureInfo.InvariantCulture, genericInterfaceDefinition));
|
||||
|
||||
private static bool IsSubClassInternal(Type initialType, Type currentType, Type check, out Type implementingType)
|
||||
{
|
||||
if (currentType == check)
|
||||
if (type.IsInterface)
|
||||
{
|
||||
implementingType = currentType;
|
||||
return true;
|
||||
}
|
||||
|
||||
// don't get interfaces for an interface unless the initial type is an interface
|
||||
if (check.IsInterface && (initialType.IsInterface || currentType == initialType))
|
||||
{
|
||||
foreach (Type t in currentType.GetInterfaces())
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
if (IsSubClassInternal(initialType, t, check, out implementingType))
|
||||
{
|
||||
// don't return the interface itself, return it's implementor
|
||||
if (check == implementingType)
|
||||
implementingType = currentType;
|
||||
Type interfaceDefinition = type.GetGenericTypeDefinition();
|
||||
|
||||
if (genericInterfaceDefinition == interfaceDefinition)
|
||||
{
|
||||
implementingType = type;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentType.IsGenericType && !currentType.IsGenericTypeDefinition)
|
||||
foreach (Type i in type.GetInterfaces())
|
||||
{
|
||||
if (IsSubClassInternal(initialType, currentType.GetGenericTypeDefinition(), check, out implementingType))
|
||||
if (i.IsGenericType)
|
||||
{
|
||||
Type interfaceDefinition = i.GetGenericTypeDefinition();
|
||||
|
||||
if (genericInterfaceDefinition == interfaceDefinition)
|
||||
{
|
||||
implementingType = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implementingType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static bool InheritsGenericClassDefinition(Type type, Type genericClassDefinition)
|
||||
{
|
||||
Type implementingType;
|
||||
return InheritsGenericClassDefinition(type, genericClassDefinition, out implementingType);
|
||||
}
|
||||
|
||||
public static bool InheritsGenericClassDefinition(Type type, Type genericClassDefinition, out Type implementingType)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(type, "type");
|
||||
ValidationUtils.ArgumentNotNull(genericClassDefinition, "genericClassDefinition");
|
||||
|
||||
if (!genericClassDefinition.IsClass || !genericClassDefinition.IsGenericTypeDefinition)
|
||||
throw new ArgumentNullException("'{0}' is not a generic class definition.".FormatWith(CultureInfo.InvariantCulture, genericClassDefinition));
|
||||
|
||||
return InheritsGenericClassDefinitionInternal(type, type, genericClassDefinition, out implementingType);
|
||||
}
|
||||
|
||||
private static bool InheritsGenericClassDefinitionInternal(Type initialType, Type currentType, Type genericClassDefinition, out Type implementingType)
|
||||
{
|
||||
if (currentType.IsGenericType)
|
||||
{
|
||||
Type currentGenericClassDefinition = currentType.GetGenericTypeDefinition();
|
||||
|
||||
if (genericClassDefinition == currentGenericClassDefinition)
|
||||
{
|
||||
implementingType = currentType;
|
||||
return true;
|
||||
@@ -177,7 +207,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsSubClassInternal(initialType, currentType.BaseType, check, out implementingType);
|
||||
return InheritsGenericClassDefinitionInternal(initialType, currentType.BaseType, genericClassDefinition, out implementingType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -194,7 +224,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
return type.GetElementType();
|
||||
}
|
||||
else if (IsSubClass(type, typeof(ICollection<>), out genericListType))
|
||||
else if (ImplementsGenericInterfaceDefinition(type, typeof(ICollection<>), out genericListType))
|
||||
{
|
||||
if (genericListType.IsGenericTypeDefinition)
|
||||
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
|
||||
@@ -216,7 +246,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
ValidationUtils.ArgumentNotNull(dictionaryType, "type");
|
||||
|
||||
Type genericDictionaryType;
|
||||
if (IsSubClass(dictionaryType, typeof(IDictionary<,>), out genericDictionaryType))
|
||||
if (ImplementsGenericInterfaceDefinition(dictionaryType, typeof(IDictionary<,>), out genericDictionaryType))
|
||||
{
|
||||
if (genericDictionaryType.IsGenericTypeDefinition)
|
||||
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
|
||||
|
||||
Reference in New Issue
Block a user