From 098d313d75d310efc3874f972c6ca20c19bcce5c Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 5 May 2014 17:37:10 +1200 Subject: [PATCH] -Parameterized object creation refactor --- .../Serialization/JsonArrayContract.cs | 20 +++++++-------- .../Serialization/JsonObjectContract.cs | 24 ++++++++++++++++-- .../JsonSerializerInternalReader.cs | 25 +++++++++++-------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs index eb97759f..35892a35 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs @@ -67,7 +67,7 @@ namespace Newtonsoft.Json.Serialization internal bool IsArray { get; private set; } internal bool ShouldCreateWrapper { get; private set; } internal bool CanDeserialize { get; private set; } - internal MethodCall ParametrizedConstructor { get; private set; } + internal MethodCall ParametrizedCreator { get; private set; } /// /// Initializes a new instance of the class. @@ -102,7 +102,7 @@ namespace Newtonsoft.Json.Serialization CreatedType = typeof(List); if (CollectionItemType != null) - ParametrizedConstructor = CollectionUtils.ResolveEnumableCollectionConstructor(underlyingType, CollectionItemType); + ParametrizedCreator = CollectionUtils.ResolveEnumableCollectionConstructor(underlyingType, CollectionItemType); IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyCollection<>)); canDeserialize = true; @@ -120,7 +120,7 @@ namespace Newtonsoft.Json.Serialization CreatedType = typeof(HashSet<>).MakeGenericType(CollectionItemType); #endif - ParametrizedConstructor = CollectionUtils.ResolveEnumableCollectionConstructor(underlyingType, CollectionItemType); + ParametrizedCreator = CollectionUtils.ResolveEnumableCollectionConstructor(underlyingType, CollectionItemType); canDeserialize = true; ShouldCreateWrapper = true; } @@ -134,9 +134,9 @@ namespace Newtonsoft.Json.Serialization CreatedType = typeof(ReadOnlyCollection<>).MakeGenericType(CollectionItemType); _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); - ParametrizedConstructor = CollectionUtils.ResolveEnumableCollectionConstructor(CreatedType, CollectionItemType); + ParametrizedCreator = CollectionUtils.ResolveEnumableCollectionConstructor(CreatedType, CollectionItemType); IsReadOnlyOrFixedSize = true; - canDeserialize = (ParametrizedConstructor != null); + canDeserialize = (ParametrizedCreator != null); } #endif else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out tempCollectionType)) @@ -146,13 +146,13 @@ namespace Newtonsoft.Json.Serialization if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IEnumerable<>))) CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); - ParametrizedConstructor = CollectionUtils.ResolveEnumableCollectionConstructor(underlyingType, CollectionItemType); + ParametrizedCreator = CollectionUtils.ResolveEnumableCollectionConstructor(underlyingType, CollectionItemType); #if !(NET35 || NET20 || NETFX_CORE) - if (ParametrizedConstructor == null && underlyingType.Name == FSharpUtils.FSharpListTypeName) + if (ParametrizedCreator == null && underlyingType.Name == FSharpUtils.FSharpListTypeName) { FSharpUtils.EnsureInitialized(underlyingType.Assembly()); - ParametrizedConstructor = FSharpUtils.CreateSeq(CollectionItemType); + ParametrizedCreator = FSharpUtils.CreateSeq(CollectionItemType); } #endif @@ -170,7 +170,7 @@ namespace Newtonsoft.Json.Serialization IsReadOnlyOrFixedSize = true; ShouldCreateWrapper = true; - canDeserialize = (ParametrizedConstructor != null); + canDeserialize = (ParametrizedCreator != null); } } else @@ -202,7 +202,7 @@ namespace Newtonsoft.Json.Serialization if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract(underlyingType, CollectionItemType, out immutableCreatedType, out immutableParameterizedCreator)) { CreatedType = immutableCreatedType; - ParametrizedConstructor = immutableParameterizedCreator; + ParametrizedCreator = immutableParameterizedCreator; IsReadOnlyOrFixedSize = true; CanDeserialize = true; } diff --git a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs index 11e11e80..4ffb2570 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs @@ -68,13 +68,31 @@ namespace Newtonsoft.Json.Serialization /// JsonConstructor attribute. /// /// The override constructor. - public ConstructorInfo OverrideConstructor { get; set; } + public ConstructorInfo OverrideConstructor + { + get { return _overrideConstructor; } + set + { + _overrideConstructor = value; + ParametrizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(value); + } + } /// /// Gets or sets the parametrized constructor used to create the object. /// /// The parametrized constructor. - public ConstructorInfo ParametrizedConstructor { get; set; } + public ConstructorInfo ParametrizedConstructor + { + get { return _parametrizedConstructor; } + set + { + _parametrizedConstructor = value; + ParametrizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(value); + } + } + + internal MethodCall ParametrizedCreator { get; set; } /// /// Gets or sets the extension data setter. @@ -87,6 +105,8 @@ namespace Newtonsoft.Json.Serialization public ExtensionDataGetter ExtensionDataGetter { get; set; } private bool? _hasRequiredOrDefaultValueProperties; + private ConstructorInfo _parametrizedConstructor; + private ConstructorInfo _overrideConstructor; internal bool HasRequiredOrDefaultValueProperties { diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 2474e316..bcefb166 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -463,7 +463,7 @@ namespace Newtonsoft.Json.Serialization if (contract.OnErrorCallbacks.Count > 0) throw JsonSerializationException.Create(reader, "Cannot call OnError on readonly list, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); - if (dictionaryContract.ParametrizedConstructor == null) + if (dictionaryContract.ParametrizedCreator == null) throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size dictionary: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); } @@ -471,7 +471,7 @@ namespace Newtonsoft.Json.Serialization if (createdFromNonDefaultConstructor) { - return dictionaryContract.ParametrizedConstructor(null , new object[] { dictionary }); + return dictionaryContract.ParametrizedCreator(null , new object[] { dictionary }); } else if (dictionary is IWrappedDictionary) { @@ -1057,7 +1057,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ createdFromNonDefaultConstructor = false; return (IDictionary)dictionary; } - else if (contract.ParametrizedConstructor != null) + else if (contract.ParametrizedCreator != null) { createdFromNonDefaultConstructor = true; return contract.CreateTemporaryDictionary(); @@ -1568,7 +1568,7 @@ To fix this error either change the environment to be fully trusted, change the } #endif - private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, string id) + private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, MethodCall constructorInfo, string id) { ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo"); @@ -1580,17 +1580,20 @@ To fix this error either change the environment to be fully trusted, change the Type objectType = contract.UnderlyingType; if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) - TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using a non-default constructor '{1}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, constructorInfo)), null); + { + string underlyingMethodName = constructorInfo.GetMethodInfo().Name; + TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using custom method '{1}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, underlyingMethodName)), null); + } IDictionary extensionData; IDictionary propertyValues = ResolvePropertyAndConstructorValues(contract, containerProperty, reader, objectType, out extensionData); - IDictionary constructorParameters = constructorInfo.GetParameters().ToDictionary(p => p, p => (object)null); + IDictionary constructorParameters = contract.ConstructorParameters.ToDictionary(p => p, p => (object)null); IDictionary remainingPropertyValues = new Dictionary(); foreach (KeyValuePair propertyValue in propertyValues) { - ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.UnderlyingName).Key; + JsonProperty matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.PropertyName, propertyValue.Key.UnderlyingName).Key; if (matchingConstructorParameter != null) constructorParameters[matchingConstructorParameter] = propertyValue.Value; else @@ -1605,7 +1608,7 @@ To fix this error either change the environment to be fully trusted, change the } } - object createdObject = constructorInfo.Invoke(constructorParameters.Values.ToArray()); + object createdObject = constructorInfo(null, constructorParameters.Values.ToArray()); if (id != null) AddReference(reader, id, createdObject); @@ -1825,7 +1828,7 @@ To fix this error either change the environment to be fully trusted, change the if (objectContract.OverrideConstructor.GetParameters().Length > 0) { createdFromNonDefaultConstructor = true; - return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.OverrideConstructor, id); + return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedCreator, id); } newObject = objectContract.OverrideConstructor.Invoke(null); @@ -1839,10 +1842,10 @@ To fix this error either change the environment to be fully trusted, change the // non-public and there is no other constructor newObject = objectContract.DefaultCreator(); } - else if (objectContract.ParametrizedConstructor != null) + else if (objectContract.ParametrizedCreator != null) { createdFromNonDefaultConstructor = true; - return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedConstructor, id); + return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedCreator, id); } if (newObject == null)