From 0c865efd96bd4de74a1aa47e3783f4a4bb778951 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 2 Sep 2014 23:29:20 +1200 Subject: [PATCH] -Fixed not matching some parameters when deserializing via a cosntructor --- .../Serialization/JsonSerializerTest.cs | 22 +++++++++++++++++++ .../JsonSerializerInternalReader.cs | 20 +++++++++++++---- .../DynamicReflectionDelegateFactory.cs | 22 +++++-------------- .../Utilities/ILGeneratorExtensions.cs | 7 ++++++ 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 92d02a0a..68c52478 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -7611,6 +7611,28 @@ Parameter name: value", } #endif + public class FooConstructor + { + [JsonProperty(PropertyName = "something_else")] + public readonly string Bar; + + public FooConstructor(string bar) + { + if (bar == null) + throw new ArgumentNullException("bar"); + + Bar = bar; + } + } + + [Test] + public void DeserializeWithConstructor() + { + const string json = @"{""something_else"":""my value""}"; + var foo = JsonConvert.DeserializeObject(json); + Assert.AreEqual("my value", foo.Bar); + } + [Test] public void SerializeCustomReferenceResolver() { diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 67befe3c..2d51728b 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -1623,7 +1623,19 @@ To fix this error either change the environment to be fully trusted, change the foreach (KeyValuePair propertyValue in propertyValues) { - JsonProperty matchingCreatorParameter = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, propertyValue.Key.PropertyName); + JsonProperty property = propertyValue.Key; + + JsonProperty matchingCreatorParameter; + if (contract.CreatorParameters.Contains(property)) + { + matchingCreatorParameter = property; + } + else + { + // check to see if a parameter with the same name as the underlying property name exists and match to that + matchingCreatorParameter = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, property.UnderlyingName); + } + if (matchingCreatorParameter != null) { int i = contract.CreatorParameters.IndexOf(matchingCreatorParameter); @@ -1637,9 +1649,9 @@ To fix this error either change the environment to be fully trusted, change the if (propertiesPresence != null) { // map from creator property to normal property - var property = propertiesPresence.Keys.FirstOrDefault(p => p.PropertyName == propertyValue.Key.PropertyName); - if (property != null) - propertiesPresence[property] = (propertyValue.Value == null) ? PropertyPresence.Null : PropertyPresence.Value; + JsonProperty presenceProperty = propertiesPresence.Keys.FirstOrDefault(p => p.PropertyName == property.PropertyName); + if (presenceProperty != null) + propertiesPresence[presenceProperty] = (propertyValue.Value == null) ? PropertyPresence.Null : PropertyPresence.Value; } } diff --git a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs index 4c251e81..6710c148 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs @@ -75,11 +75,11 @@ namespace Newtonsoft.Json.Utilities Label argsOk = generator.DefineLabel(); + // throw an error if the number of argument values doesn't match method parameters generator.Emit(OpCodes.Ldarg, argsIndex); generator.Emit(OpCodes.Ldlen); generator.Emit(OpCodes.Ldc_I4, args.Length); generator.Emit(OpCodes.Beq, argsOk); - generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes)); generator.Emit(OpCodes.Throw); @@ -104,9 +104,7 @@ namespace Newtonsoft.Json.Utilities // don't need to set variable for 'out' parameter if (!parameter.IsOut) { - generator.Emit(OpCodes.Ldarg, argsIndex); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldelem_Ref); + generator.PushArrayInstance(argsIndex, i); if (parameterType.IsValueType()) { @@ -123,9 +121,7 @@ namespace Newtonsoft.Json.Utilities // parameter has value, get value from array again and unbox and set to variable generator.MarkLabel(skipSettingDefault); - generator.Emit(OpCodes.Ldarg, argsIndex); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldelem_Ref); + generator.PushArrayInstance(argsIndex, i); generator.UnboxIfNeeded(parameterType); generator.Emit(OpCodes.Stloc, localVariableCount); @@ -145,9 +141,7 @@ namespace Newtonsoft.Json.Utilities } else if (parameterType.IsValueType()) { - generator.Emit(OpCodes.Ldarg, argsIndex); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldelem_Ref); + generator.PushArrayInstance(argsIndex, i); // have to check that value type parameters aren't null // otherwise they will error when unboxed @@ -166,9 +160,7 @@ namespace Newtonsoft.Json.Utilities // parameter has value, get value from array again and unbox generator.MarkLabel(skipSettingDefault); - generator.Emit(OpCodes.Ldarg, argsIndex); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldelem_Ref); + generator.PushArrayInstance(argsIndex, i); generator.UnboxIfNeeded(parameterType); // parameter finished, we out! @@ -177,9 +169,7 @@ namespace Newtonsoft.Json.Utilities } else { - generator.Emit(OpCodes.Ldarg, argsIndex); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldelem_Ref); + generator.PushArrayInstance(argsIndex, i); generator.UnboxIfNeeded(parameterType); } diff --git a/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs b/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs index cbed7db6..30fd02b7 100644 --- a/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs +++ b/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs @@ -41,6 +41,13 @@ namespace Newtonsoft.Json.Utilities generator.Emit(OpCodes.Castclass, type); } + public static void PushArrayInstance(this ILGenerator generator, int argsIndex, int arrayIndex) + { + generator.Emit(OpCodes.Ldarg, argsIndex); + generator.Emit(OpCodes.Ldc_I4, arrayIndex); + generator.Emit(OpCodes.Ldelem_Ref); + } + public static void BoxIfNeeded(this ILGenerator generator, Type type) { if (type.IsValueType())