-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:
JamesNK
2008-09-14 10:30:38 +00:00
parent b991969d65
commit e8654d8c03
13 changed files with 442 additions and 117 deletions
@@ -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" />
+131 -37
View File
@@ -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
}
}
+43 -22
View File
@@ -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;
+73 -16
View File
@@ -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;
}
}
}
+6 -7
View File
@@ -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);
}
}
}
+9 -2
View File
@@ -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));