private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id) { contract.InvokeOnDeserializing(newObject, Serializer.Context); // only need to keep a track of properies presence if they are required or a value should be defaulted if missing Dictionary<JsonProperty, PropertyPresence> propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer.DefaultValueHandling, DefaultValueHandling.Populate)) ? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None) : null; if (id != null) Serializer.ReferenceResolver.AddReference(this, id, newObject); int initialDepth = reader.Depth; do { switch (reader.TokenType) { case JsonToken.PropertyName: { string memberName = reader.Value.ToString(); try { // attempt exact case match first // then try match ignoring case JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName); if (property == null) { if (Serializer.MissingMemberHandling == MissingMemberHandling.Error) throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name)); reader.Skip(); continue; } if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, member); if (!ReadForType(reader, property.PropertyContract, propertyConverter != null)) throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); SetPropertyPresence(reader, property, propertiesPresence); SetPropertyValue(property, propertyConverter, contract, member, reader, newObject); } catch (Exception ex) { if (IsErrorHandled(newObject, contract, memberName, reader.Path, ex)) HandleError(reader, true, initialDepth); else throw; } } break; case JsonToken.EndObject: { EndObject(newObject, reader, contract, initialDepth, propertiesPresence); contract.InvokeOnDeserialized(newObject, Serializer.Context); return newObject; } case JsonToken.Comment: // ignore break; default: throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType); } } while (reader.Read()); throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); }
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, string id) { ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo"); Type objectType = contract.UnderlyingType; IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndConstructorValues(contract, containerProperty, reader, objectType); IDictionary<ParameterInfo, object> constructorParameters = constructorInfo.GetParameters().ToDictionary(p => p, p => (object) null); IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>(); foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues) { ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.UnderlyingName).Key; if (matchingConstructorParameter != null) constructorParameters[matchingConstructorParameter] = propertyValue.Value; else remainingPropertyValues.Add(propertyValue); } object createdObject = constructorInfo.Invoke(constructorParameters.Values.ToArray()); if (id != null) Serializer.ReferenceResolver.AddReference(this, id, createdObject); contract.InvokeOnDeserializing(createdObject, Serializer.Context); // go through unused values and set the newly created object's properties foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues) { JsonProperty property = remainingPropertyValue.Key; object value = remainingPropertyValue.Value; if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value)) { property.ValueProvider.SetValue(createdObject, value); } else if (!property.Writable && value != null) { // handle readonly collection/dictionary properties JsonContract propertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType); if (propertyContract.ContractType == JsonContractType.Array) { JsonArrayContract propertyArrayContract = (JsonArrayContract)propertyContract; object createdObjectCollection = property.ValueProvider.GetValue(createdObject); if (createdObjectCollection != null) { IWrappedCollection createdObjectCollectionWrapper = propertyArrayContract.CreateWrapper(createdObjectCollection); IWrappedCollection newValues = propertyArrayContract.CreateWrapper(value); foreach (object newValue in newValues) { createdObjectCollectionWrapper.Add(newValue); } } } else if (propertyContract.ContractType == JsonContractType.Dictionary) { JsonDictionaryContract jsonDictionaryContract = (JsonDictionaryContract)propertyContract; object createdObjectDictionary = property.ValueProvider.GetValue(createdObject); if (createdObjectDictionary != null) { IWrappedDictionary createdObjectDictionaryWrapper = jsonDictionaryContract.CreateWrapper(createdObjectDictionary); IWrappedDictionary newValues = jsonDictionaryContract.CreateWrapper(value); foreach (DictionaryEntry newValue in newValues) { createdObjectDictionaryWrapper.Add(newValue.Key, newValue.Value); } } } } } contract.InvokeOnDeserialized(createdObject, Serializer.Context); return createdObject; }