-Performance
-Added ConstructorHandling to allow object creation using non-public default constructors
This commit is contained in:
@@ -72,6 +72,7 @@
|
||||
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
|
||||
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
|
||||
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
|
||||
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
|
||||
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
|
||||
<Compile Include="Serialization\JsonSerializerTest.cs" />
|
||||
<Compile Include="Serialization\MissingMemberHandlingTests.cs" />
|
||||
@@ -121,6 +122,8 @@
|
||||
<Compile Include="TestObjects\ObjectArrayPropertyTest.cs" />
|
||||
<Compile Include="TestObjects\PersonRaw.cs" />
|
||||
<Compile Include="TestObjects\PhoneNumber.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorWithPublicParametizedConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PrivateMembersClass.cs" />
|
||||
<Compile Include="TestObjects\PropertyCase.cs" />
|
||||
<Compile Include="TestObjects\RequestOnly.cs" />
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JTypeDescriptionProviderTests.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
|
||||
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
|
||||
<Compile Include="TestObjects\Content.cs" />
|
||||
<Compile Include="TestObjects\DictionaryInterfaceClass.cs" />
|
||||
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
|
||||
@@ -86,6 +87,8 @@
|
||||
<Compile Include="TestObjects\NonRequest.cs" />
|
||||
<Compile Include="TestObjects\ObjectArrayPropertyTest.cs" />
|
||||
<Compile Include="Serialization\PopulateTests.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorWithPublicParametizedConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PropertyCase.cs" />
|
||||
<Compile Include="TestObjects\RequestOnly.cs" />
|
||||
<Compile Include="TestObjects\RoleTransfer.cs" />
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<Compile Include="Schema\JsonSchemaModelBuilderTests.cs" />
|
||||
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
|
||||
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
|
||||
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
|
||||
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
|
||||
<Compile Include="Serialization\JsonSerializerTest.cs" />
|
||||
<Compile Include="Serialization\MissingMemberHandlingTests.cs" />
|
||||
@@ -127,6 +128,8 @@
|
||||
<Compile Include="TestObjects\ObjectArrayPropertyTest.cs" />
|
||||
<Compile Include="TestObjects\PersonRaw.cs" />
|
||||
<Compile Include="TestObjects\PhoneNumber.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorWithPublicParametizedConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PrivateMembersClass.cs" />
|
||||
<Compile Include="TestObjects\PropertyCase.cs" />
|
||||
<Compile Include="TestObjects\RequestOnly.cs" />
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptorTests.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JTypeDescriptionProviderTests.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JTypeDescriptorTests.cs" />
|
||||
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\PrivateConstructorWithPublicParametizedConstructorTestClass.cs" />
|
||||
<Compile Include="TestObjects\Content.cs" />
|
||||
<Compile Include="TestObjects\DateTimeErrorObjectCollection.cs" />
|
||||
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
timed.Stop();
|
||||
|
||||
Console.WriteLine("Serialize method: {0}", method);
|
||||
Console.WriteLine("Deserialize method: {0}", method);
|
||||
Console.WriteLine("{0} ms", timed.ElapsedMilliseconds);
|
||||
Console.WriteLine(value);
|
||||
Console.WriteLine();
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.Serialization
|
||||
{
|
||||
public class ConstructorHandlingTests : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Unable to find a constructor to use for type Newtonsoft.Json.Tests.Serialization.PrivateConstructorTestClass. A class should either have a default constructor or only one constructor with arguments.")]
|
||||
public void FailWithPrivateConstructorAndDefault()
|
||||
{
|
||||
string json = @"{Name:""Name!""}";
|
||||
|
||||
JsonConvert.DeserializeObject<PrivateConstructorTestClass>(json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SuccessWithPrivateConstructorAndAllowNonPublic()
|
||||
{
|
||||
string json = @"{Name:""Name!""}";
|
||||
|
||||
PrivateConstructorTestClass c = JsonConvert.DeserializeObject<PrivateConstructorTestClass>(json,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
|
||||
});
|
||||
Assert.IsNotNull(c);
|
||||
Assert.AreEqual("Name!", c.Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(TargetInvocationException))]
|
||||
public void FailWithPrivateConstructorPlusParametizedAndDefault()
|
||||
{
|
||||
string json = @"{Name:""Name!""}";
|
||||
|
||||
PrivateConstructorWithPublicParametizedConstructorTestClass c = JsonConvert.DeserializeObject<PrivateConstructorWithPublicParametizedConstructorTestClass>(json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SuccessWithPrivateConstructorPlusParametizedAndAllowNonPublic()
|
||||
{
|
||||
string json = @"{Name:""Name!""}";
|
||||
|
||||
PrivateConstructorWithPublicParametizedConstructorTestClass c = JsonConvert.DeserializeObject<PrivateConstructorWithPublicParametizedConstructorTestClass>(json,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
|
||||
});
|
||||
Assert.IsNotNull(c);
|
||||
Assert.AreEqual("Name!", c.Name);
|
||||
Assert.AreEqual(1, c.Age);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1756,7 +1756,7 @@ keyword such as type of business.""
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unable to determine which constructor to use for type Newtonsoft.Json.Tests.TestObjects.Event. A class with no default constructor should have only one constructor with arguments.")]
|
||||
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unable to find a constructor to use for type Newtonsoft.Json.Tests.TestObjects.Event. A class should either have a default constructor or only one constructor with arguments.")]
|
||||
public void FailWhenClassWithNoDefaultConstructorHasMultipleConstructorsWithArguments()
|
||||
{
|
||||
string json = @"{""sublocation"":""AlertEmailSender.Program.Main"",""userId"":0,""type"":0,""summary"":""Loading settings variables"",""details"":null,""stackTrace"":"" at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)\r\n at System.Environment.get_StackTrace()\r\n at mr.Logging.Event..ctor(String summary) in C:\\Projects\\MRUtils\\Logging\\Event.vb:line 71\r\n at AlertEmailSender.Program.Main(String[] args) in C:\\Projects\\AlertEmailSender\\AlertEmailSender\\Program.cs:line 25"",""tag"":null,""time"":""\/Date(1249591032026-0400)\/""}";
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#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
|
||||
|
||||
namespace Newtonsoft.Json.Tests.TestObjects
|
||||
{
|
||||
public class PrivateConstructorTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
|
||||
private PrivateConstructorTestClass()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#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;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.TestObjects
|
||||
{
|
||||
public class PrivateConstructorWithPublicParametizedConstructorTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
|
||||
private PrivateConstructorWithPublicParametizedConstructorTestClass()
|
||||
{
|
||||
Age = 1;
|
||||
}
|
||||
|
||||
public PrivateConstructorWithPublicParametizedConstructorTestClass(string dummy)
|
||||
{
|
||||
throw new Exception("Should never get here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 how constructors are used when initializing objects during deserialization by the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
public enum ConstructorHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// First attempt to use the public default constructor then fall back to single paramatized constructor.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
/// <summary>
|
||||
/// Allow Json.NET to use a non-public default constructor.
|
||||
/// </summary>
|
||||
AllowNonPublicDefaultConstructor = 1
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ namespace Newtonsoft.Json
|
||||
private ObjectCreationHandling _objectCreationHandling;
|
||||
private NullValueHandling _nullValueHandling;
|
||||
private DefaultValueHandling _defaultValueHandling;
|
||||
private ConstructorHandling _constructorHandling;
|
||||
private JsonConverterCollection _converters;
|
||||
private IContractResolver _contractResolver;
|
||||
private IReferenceResolver _referenceResolver;
|
||||
@@ -204,6 +205,22 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how constructors are used during deserialization.
|
||||
/// </summary>
|
||||
/// <value>The constructor handling.</value>
|
||||
public virtual ConstructorHandling ConstructorHandling
|
||||
{
|
||||
get { return _constructorHandling; }
|
||||
set
|
||||
{
|
||||
if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
|
||||
_constructorHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection <see cref="JsonConverter"/> that will be used during serialization.
|
||||
/// </summary>
|
||||
@@ -247,6 +264,7 @@ namespace Newtonsoft.Json
|
||||
_defaultValueHandling = JsonSerializerSettings.DefaultDefaultValueHandling;
|
||||
_objectCreationHandling = JsonSerializerSettings.DefaultObjectCreationHandling;
|
||||
_preserveReferencesHandling = JsonSerializerSettings.DefaultPreserveReferencesHandling;
|
||||
_constructorHandling = JsonSerializerSettings.DefaultConstructorHandling;
|
||||
_typeNameHandling = JsonSerializerSettings.DefaultTypeNameHandling;
|
||||
_binder = DefaultSerializationBinder.Instance;
|
||||
}
|
||||
@@ -272,6 +290,7 @@ namespace Newtonsoft.Json
|
||||
jsonSerializer.ObjectCreationHandling = settings.ObjectCreationHandling;
|
||||
jsonSerializer.NullValueHandling = settings.NullValueHandling;
|
||||
jsonSerializer.DefaultValueHandling = settings.DefaultValueHandling;
|
||||
jsonSerializer.ConstructorHandling = settings.ConstructorHandling;
|
||||
|
||||
if (settings.ContractResolver != null)
|
||||
jsonSerializer.ContractResolver = settings.ContractResolver;
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Newtonsoft.Json
|
||||
internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;
|
||||
internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;
|
||||
internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;
|
||||
internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;
|
||||
internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;
|
||||
|
||||
/// <summary>
|
||||
@@ -61,6 +62,11 @@ namespace Newtonsoft.Json
|
||||
/// </summary>
|
||||
/// <value>The type name handling.</value>
|
||||
public TypeNameHandling TypeNameHandling { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets how constructors are used during deserialization.
|
||||
/// </summary>
|
||||
/// <value>The constructor handling.</value>
|
||||
public ConstructorHandling ConstructorHandling { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contract resolver used by the serializer when
|
||||
|
||||
@@ -347,6 +347,10 @@ namespace Newtonsoft.Json
|
||||
SetStateBasedOnCurrent();
|
||||
ClearCurrentChar();
|
||||
return false;
|
||||
case ' ':
|
||||
// eat whitespace
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
{
|
||||
@@ -379,6 +383,9 @@ namespace Newtonsoft.Json
|
||||
case ',':
|
||||
SetToken(JsonToken.Undefined);
|
||||
return true;
|
||||
case ' ':
|
||||
// eat
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
{
|
||||
@@ -547,6 +554,9 @@ namespace Newtonsoft.Json
|
||||
case ')':
|
||||
SetToken(JsonToken.EndConstructor);
|
||||
return true;
|
||||
case ' ':
|
||||
// eat
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
{
|
||||
@@ -571,7 +581,7 @@ namespace Newtonsoft.Json
|
||||
private bool EatWhitespace(bool oneOrMore)
|
||||
{
|
||||
bool whitespace = false;
|
||||
while (char.IsWhiteSpace(_currentChar))
|
||||
while (_currentChar == ' ' || char.IsWhiteSpace(_currentChar))
|
||||
{
|
||||
whitespace = true;
|
||||
MoveNext();
|
||||
@@ -736,6 +746,8 @@ namespace Newtonsoft.Json
|
||||
if (CurrentState == State.Constructor || CurrentState == State.ConstructorStart)
|
||||
return true;
|
||||
break;
|
||||
case ' ':
|
||||
return true;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
return true;
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConstructorHandling.cs" />
|
||||
<Compile Include="Converters\BinaryConverter.cs" />
|
||||
<Compile Include="Converters\CustomCreationConverter.cs" />
|
||||
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConstructorHandling.cs" />
|
||||
<Compile Include="Converters\BinaryConverter.cs" />
|
||||
<Compile Include="Converters\CustomCreationConverter.cs" />
|
||||
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
<Reference Include="System.Windows.Browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConstructorHandling.cs" />
|
||||
<Compile Include="Converters\BinaryConverter.cs" />
|
||||
<Compile Include="Converters\CustomCreationConverter.cs" />
|
||||
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
<Compile Include="Converters\CustomCreationConverter.cs" />
|
||||
<Compile Include="Converters\EntityKeyMemberConverter.cs" />
|
||||
<Compile Include="Converters\StringEnumConverter.cs" />
|
||||
<Compile Include="ConstructorHandling.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JTypeDescriptionProvider.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JTypeDescriptor.cs" />
|
||||
|
||||
@@ -140,10 +140,22 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType);
|
||||
contract.Properties.AddRange(CreateProperties(contract));
|
||||
if (contract.DefaultContstructor == null || contract.DefaultContstructor.IsPrivate)
|
||||
contract.ParametrizedConstructor = GetParametrizedConstructor(objectType);
|
||||
|
||||
return contract;
|
||||
}
|
||||
|
||||
private ConstructorInfo GetParametrizedConstructor(Type objectType)
|
||||
{
|
||||
ConstructorInfo[] constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (constructors.Length == 1)
|
||||
return constructors[0];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private void InitializeContract(JsonContract contract)
|
||||
{
|
||||
JsonContainerAttribute containerAttribute = JsonTypeReflector.GetJsonContainerAttribute(contract.UnderlyingType);
|
||||
@@ -161,6 +173,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
#endif
|
||||
|
||||
contract.DefaultContstructor =
|
||||
ReflectionUtils.GetDefaultConstructor(contract.CreatedType, false) ??
|
||||
ReflectionUtils.GetDefaultConstructor(contract.CreatedType, true);
|
||||
|
||||
foreach (MethodInfo method in contract.UnderlyingType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
Type prevAttributeType = null;
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Collections;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
@@ -34,9 +36,13 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
public class JsonArrayContract : JsonContract
|
||||
{
|
||||
internal Type CollectionTypeToCreate { get; private set; }
|
||||
internal Type CollectionItemType { get; private set; }
|
||||
|
||||
private bool _isCollectionItemTypeNullableType;
|
||||
private Type _genericCollectionDefinitionType;
|
||||
private Type _genericWrapperType;
|
||||
private ConstructorInfo _genericWrapperConstructor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
|
||||
/// </summary>
|
||||
@@ -44,17 +50,40 @@ namespace Newtonsoft.Json.Serialization
|
||||
public JsonArrayContract(Type underlyingType)
|
||||
: base(underlyingType)
|
||||
{
|
||||
CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
|
||||
|
||||
if (IsTypeGenericCollectionInterface(UnderlyingType))
|
||||
if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType))
|
||||
{
|
||||
Type itemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
|
||||
CollectionTypeToCreate = ReflectionUtils.MakeGenericType(typeof(List<>), itemType);
|
||||
CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
CollectionTypeToCreate = UnderlyingType;
|
||||
CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
|
||||
}
|
||||
|
||||
if (CollectionItemType != null)
|
||||
_isCollectionItemTypeNullableType = ReflectionUtils.IsNullableType(CollectionItemType);
|
||||
|
||||
if (IsTypeGenericCollectionInterface(UnderlyingType))
|
||||
{
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(List<>), CollectionItemType);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatedType = UnderlyingType;
|
||||
}
|
||||
}
|
||||
|
||||
internal IWrappedCollection CreateWrapper(object list)
|
||||
{
|
||||
if (list is IList && (CollectionItemType == null || !_isCollectionItemTypeNullableType))
|
||||
return new CollectionWrapper<object>((IList)list);
|
||||
|
||||
if (_genericWrapperType == null)
|
||||
{
|
||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType);
|
||||
_genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||
}
|
||||
|
||||
return (IWrappedCollection)_genericWrapperConstructor.Invoke(new[] { list });
|
||||
}
|
||||
|
||||
private bool IsTypeGenericCollectionInterface(Type type)
|
||||
|
||||
@@ -40,6 +40,13 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
/// <value>The underlying type for the contract.</value>
|
||||
public Type UnderlyingType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type created during deserialization.
|
||||
/// </summary>
|
||||
/// <value>The type created during deserialization.</value>
|
||||
public Type CreatedType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this type contract is serialized as a reference.
|
||||
/// </summary>
|
||||
@@ -72,6 +79,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
public MethodInfo OnSerializing { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default contstructor used to create the object.
|
||||
/// </summary>
|
||||
/// <value>The default contstructor.</value>
|
||||
public ConstructorInfo DefaultContstructor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the method called when an error is thrown during the serialization of the object.
|
||||
/// </summary>
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Collections;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
@@ -34,10 +36,13 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
public class JsonDictionaryContract : JsonContract
|
||||
{
|
||||
internal Type DictionaryTypeToCreate { get; private set; }
|
||||
internal Type DictionaryKeyType { get; private set; }
|
||||
internal Type DictionaryValueType { get; private set; }
|
||||
|
||||
private Type _genericCollectionDefinitionType;
|
||||
private Type _genericWrapperType;
|
||||
private ConstructorInfo _genericWrapperConstructor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
|
||||
/// </summary>
|
||||
@@ -47,21 +52,43 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
Type keyType;
|
||||
Type valueType;
|
||||
ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType);
|
||||
if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType))
|
||||
{
|
||||
keyType = _genericCollectionDefinitionType.GetGenericArguments()[0];
|
||||
valueType = _genericCollectionDefinitionType.GetGenericArguments()[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType);
|
||||
}
|
||||
|
||||
DictionaryKeyType = keyType;
|
||||
DictionaryValueType = valueType;
|
||||
|
||||
if (IsTypeGenericDictionaryInterface(UnderlyingType))
|
||||
{
|
||||
DictionaryTypeToCreate = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(Dictionary<,>), keyType, valueType);
|
||||
}
|
||||
else
|
||||
{
|
||||
DictionaryTypeToCreate = underlyingType;
|
||||
CreatedType = underlyingType;
|
||||
}
|
||||
}
|
||||
|
||||
internal IWrappedDictionary CreateWrapper(object dictionary)
|
||||
{
|
||||
if (dictionary is IDictionary)
|
||||
return new DictionaryWrapper<object, object>((IDictionary)dictionary);
|
||||
|
||||
if (_genericWrapperType == null)
|
||||
{
|
||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(DictionaryWrapper<,>), DictionaryKeyType, DictionaryValueType);
|
||||
_genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||
}
|
||||
|
||||
return (IWrappedDictionary)_genericWrapperConstructor.Invoke(new[] { dictionary });
|
||||
}
|
||||
|
||||
private bool IsTypeGenericDictionaryInterface(Type type)
|
||||
{
|
||||
if (!type.IsGenericType)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
@@ -44,6 +45,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <value>The object's properties.</value>
|
||||
public JsonPropertyCollection Properties { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parametrized constructor used to create the object.
|
||||
/// </summary>
|
||||
/// <value>The parametrized constructor.</value>
|
||||
public ConstructorInfo ParametrizedConstructor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonObjectContract"/> class.
|
||||
/// </summary>
|
||||
@@ -52,6 +59,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
: base(underlyingType)
|
||||
{
|
||||
Properties = new JsonPropertyCollection();
|
||||
CreatedType = underlyingType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,7 +435,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private object CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, string id)
|
||||
{
|
||||
IWrappedDictionary dictionary = CollectionUtils.CreateDictionaryWrapper(Activator.CreateInstance(contract.DictionaryTypeToCreate));
|
||||
IWrappedDictionary dictionary = contract.CreateWrapper(contract.DefaultContstructor.Invoke(null));
|
||||
|
||||
PopulateDictionary(dictionary, reader, contract, id);
|
||||
|
||||
@@ -488,7 +488,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
private object CreateAndPopulateList(JsonReader reader, string reference, JsonArrayContract contract)
|
||||
{
|
||||
return CollectionUtils.CreateAndPopulateList(contract.CollectionTypeToCreate, (l, isTemporaryListReference) =>
|
||||
return CollectionUtils.CreateAndPopulateList(contract.CreatedType, (l, isTemporaryListReference) =>
|
||||
{
|
||||
if (reference != null && isTemporaryListReference)
|
||||
throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
@@ -500,7 +500,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (contract.OnError != null && isTemporaryListReference)
|
||||
throw new JsonSerializationException("Cannot call OnError on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
PopulateList(CollectionUtils.CreateCollectionWrapper(l), reader, reference, contract);
|
||||
PopulateList(contract.CreateWrapper(l), reader, reference, contract);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -556,30 +556,24 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (contract.UnderlyingType.IsInterface || contract.UnderlyingType.IsAbstract)
|
||||
throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
if (ReflectionUtils.HasDefaultConstructor(contract.UnderlyingType))
|
||||
if (contract.DefaultContstructor != null &&
|
||||
(contract.DefaultContstructor.IsPublic || _serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
|
||||
{
|
||||
newObject = Activator.CreateInstance(contract.UnderlyingType);
|
||||
newObject = contract.DefaultContstructor.Invoke(null);
|
||||
|
||||
PopulateObject(newObject, reader, contract, id);
|
||||
return newObject;
|
||||
}
|
||||
|
||||
return CreateObjectFromNonDefaultConstructor(contract, reader);
|
||||
return CreateObjectFromNonDefaultConstructor(reader, contract, id);
|
||||
}
|
||||
|
||||
private object CreateObjectFromNonDefaultConstructor(JsonObjectContract contract, JsonReader reader)
|
||||
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, string id)
|
||||
{
|
||||
Type objectType = contract.UnderlyingType;
|
||||
|
||||
ConstructorInfo[] constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (constructors.Length == 0)
|
||||
throw new JsonSerializationException("Could not find a public constructor for type {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
if (constructors.Length > 1)
|
||||
throw new JsonSerializationException("Unable to determine which constructor to use for type {0}. A class with no default constructor should have only one constructor with arguments.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
|
||||
// object should have a single constructor
|
||||
ConstructorInfo c = constructors[0];
|
||||
if (contract.ParametrizedConstructor == null)
|
||||
throw new JsonSerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor or only one constructor with arguments.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
|
||||
// create a dictionary to put retrieved values into
|
||||
IDictionary<JsonProperty, object> propertyValues = contract.Properties.Where(p => !p.Ignored).ToDictionary(kv => kv, kv => (object)null);
|
||||
@@ -621,7 +615,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
} while (!exit && reader.Read());
|
||||
|
||||
IDictionary<ParameterInfo, object> constructorParameters = c.GetParameters().ToDictionary(p => p, p => (object)null);
|
||||
IDictionary<ParameterInfo, object> constructorParameters = contract.ParametrizedConstructor.GetParameters().ToDictionary(p => p, p => (object)null);
|
||||
IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
|
||||
|
||||
foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
|
||||
@@ -633,7 +627,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
remainingPropertyValues.Add(propertyValue);
|
||||
}
|
||||
|
||||
object createdObject = ReflectionUtils.CreateInstance(objectType, constructorParameters.Values.ToArray());
|
||||
object createdObject = contract.ParametrizedConstructor.Invoke(constructorParameters.Values.ToArray());
|
||||
|
||||
if (id != null)
|
||||
_serializer.ReferenceResolver.AddReference(id, createdObject);
|
||||
|
||||
contract.InvokeOnDeserializing(createdObject);
|
||||
|
||||
// go through unused values and set the newly created object's properties
|
||||
|
||||
@@ -94,6 +94,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
set { _serializer.TypeNameHandling = value; }
|
||||
}
|
||||
|
||||
public override ConstructorHandling ConstructorHandling
|
||||
{
|
||||
get { return _serializer.ConstructorHandling; }
|
||||
set { _serializer.ConstructorHandling = value; }
|
||||
}
|
||||
|
||||
public override SerializationBinder Binder
|
||||
{
|
||||
get { return _serializer.Binder; }
|
||||
|
||||
@@ -334,17 +334,6 @@ namespace Newtonsoft.Json.Utilities
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T[] CreateArray<T>(IEnumerable<T> enumerable)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
|
||||
|
||||
if (enumerable is T[])
|
||||
return (T[])enumerable;
|
||||
|
||||
List<T> tempList = new List<T>(enumerable);
|
||||
return tempList.ToArray();
|
||||
}
|
||||
|
||||
public static IList CreateGenericList(Type listType)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(listType, "listType");
|
||||
|
||||
@@ -55,13 +55,30 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
|
||||
public static bool HasDefaultConstructor(Type t)
|
||||
{
|
||||
return HasDefaultConstructor(t, false);
|
||||
}
|
||||
|
||||
public static bool HasDefaultConstructor(Type t, bool nonPublic)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(t, "t");
|
||||
|
||||
if (t.IsValueType)
|
||||
return true;
|
||||
|
||||
return (t.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null) != null);
|
||||
return (GetDefaultConstructor(t, nonPublic) != null);
|
||||
}
|
||||
|
||||
public static ConstructorInfo GetDefaultConstructor(Type t)
|
||||
{
|
||||
return GetDefaultConstructor(t, false);
|
||||
}
|
||||
|
||||
public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic)
|
||||
{
|
||||
BindingFlags accessModifier = (!nonPublic) ? BindingFlags.Public : BindingFlags.NonPublic;
|
||||
|
||||
return t.GetConstructor(accessModifier | BindingFlags.Instance, null, new Type[0], null);
|
||||
}
|
||||
|
||||
public static bool IsNullable(Type t)
|
||||
@@ -575,20 +592,11 @@ namespace Newtonsoft.Json.Utilities
|
||||
ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes");
|
||||
ValidationUtils.ArgumentNotNull(instanceCreator, "createInstance");
|
||||
|
||||
Type specificType = MakeGenericType(genericTypeDefinition, CollectionUtils.CreateArray(innerTypes));
|
||||
Type specificType = MakeGenericType(genericTypeDefinition, innerTypes.ToArray());
|
||||
|
||||
return instanceCreator(specificType, args);
|
||||
}
|
||||
|
||||
static object CreateInstance(this Assembly a, string typeName, params object[] pars)
|
||||
{
|
||||
var t = a.GetType(typeName);
|
||||
var c = t.GetConstructor(pars.Select(p => p.GetType()).ToArray());
|
||||
if (c == null)
|
||||
return null;
|
||||
return c.Invoke(pars);
|
||||
}
|
||||
|
||||
public static bool IsCompatibleValue(object value, Type type)
|
||||
{
|
||||
if (value == null && IsNullable(type))
|
||||
|
||||
Reference in New Issue
Block a user