private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor<object> creator, string id) { ValidationUtils.ArgumentNotNull(creator, "creator"); // 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; Type objectType = contract.UnderlyingType; if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { string parameters = string.Join(", ", contract.CreatorParameters.Select(p => p.PropertyName).ToArray()); TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using creator with parameters: {1}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, parameters)), null); } IDictionary<string, object> extensionData; IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType, out extensionData); object[] creatorParameterValues = new object[contract.CreatorParameters.Count]; IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>(); foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues) { JsonProperty matchingCreatorParameter = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, propertyValue.Key.PropertyName); if (matchingCreatorParameter != null) { int i = contract.CreatorParameters.IndexOf(matchingCreatorParameter); creatorParameterValues[i] = propertyValue.Value; } else { remainingPropertyValues.Add(propertyValue); } 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; } } object createdObject = creator(creatorParameterValues); if (id != null) AddReference(reader, id, createdObject); OnDeserializing(reader, contract, createdObject); // 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(property, 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 dictionaryContract = (JsonDictionaryContract)propertyContract; object createdObjectDictionary = property.ValueProvider.GetValue(createdObject); if (createdObjectDictionary != null) { IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary; IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value; foreach (DictionaryEntry newValue in newValues) { targetDictionary.Add(newValue.Key, newValue.Value); } } } } } if (extensionData != null) { foreach (KeyValuePair<string, object> e in extensionData) { contract.ExtensionDataSetter(createdObject, e.Key, e.Value); } } EndObject(createdObject, reader, contract, reader.Depth, propertiesPresence); OnDeserialized(reader, contract, createdObject); return createdObject; }
private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o) { if (contract.ExtensionDataSetter != null) { try { object value = CreateValueInternal(reader, null, null, null, contract, member, null); contract.ExtensionDataSetter(o, memberName, value); } catch (Exception ex) { throw JsonSerializationException.Create(reader, "Error setting value in extension data for type '{0}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType), ex); } } else { reader.Skip(); } }
private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor<object> creator, string id) { ValidationUtils.ArgumentNotNull(creator, nameof(creator)); // only need to keep a track of properies presence if they are required or a value should be defaulted if missing bool trackPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate)); Type objectType = contract.UnderlyingType; if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { string parameters = string.Join(", ", contract.CreatorParameters.Select(p => p.PropertyName).ToArray()); TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using creator with parameters: {1}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, parameters)), null); } List<CreatorPropertyContext> propertyContexts = ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType); if (trackPresence) { foreach (JsonProperty property in contract.Properties) { if (propertyContexts.All(p => p.Property != property)) { propertyContexts.Add(new CreatorPropertyContext { Property = property, Name = property.PropertyName, Presence = PropertyPresence.None }); } } } object[] creatorParameterValues = new object[contract.CreatorParameters.Count]; foreach (CreatorPropertyContext context in propertyContexts) { // set presence of read values if (trackPresence) { if (context.Property != null && context.Presence == null) { object v = context.Value; PropertyPresence propertyPresence; if (v == null) { propertyPresence = PropertyPresence.Null; } else if (v is string) { propertyPresence = CoerceEmptyStringToNull(context.Property.PropertyType, context.Property.PropertyContract, (string)v) ? PropertyPresence.Null : PropertyPresence.Value; } else { propertyPresence = PropertyPresence.Value; } context.Presence = propertyPresence; } } JsonProperty constructorProperty = context.ConstructorProperty; if (constructorProperty == null && context.Property != null) { constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, context.Property.UnderlyingName); } if (constructorProperty != null && !constructorProperty.Ignored) { // handle giving default values to creator parameters // this needs to happen before the call to creator if (trackPresence) { if (context.Presence == PropertyPresence.None || context.Presence == PropertyPresence.Null) { if (constructorProperty.PropertyContract == null) { constructorProperty.PropertyContract = GetContractSafe(constructorProperty.PropertyType); } if (HasFlag(constructorProperty.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate)) { context.Value = EnsureType( reader, constructorProperty.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, constructorProperty.PropertyContract, constructorProperty.PropertyType); } } } int i = contract.CreatorParameters.IndexOf(constructorProperty); creatorParameterValues[i] = context.Value; context.Used = true; } } object createdObject = creator(creatorParameterValues); if (id != null) { AddReference(reader, id, createdObject); } OnDeserializing(reader, contract, createdObject); // go through unused values and set the newly created object's properties foreach (CreatorPropertyContext context in propertyContexts) { if (context.Used || context.Property == null || context.Property.Ignored || context.Presence == PropertyPresence.None) { continue; } JsonProperty property = context.Property; object value = context.Value; if (ShouldSetPropertyValue(property, value)) { property.ValueProvider.SetValue(createdObject, value); context.Used = true; } 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 dictionaryContract = (JsonDictionaryContract)propertyContract; object createdObjectDictionary = property.ValueProvider.GetValue(createdObject); if (createdObjectDictionary != null) { IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary; IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value; foreach (DictionaryEntry newValue in newValues) { targetDictionary.Add(newValue.Key, newValue.Value); } } } context.Used = true; } } if (contract.ExtensionDataSetter != null) { foreach (CreatorPropertyContext propertyValue in propertyContexts) { if (!propertyValue.Used) { contract.ExtensionDataSetter(createdObject, propertyValue.Name, propertyValue.Value); } } } if (trackPresence) { foreach (CreatorPropertyContext context in propertyContexts) { if (context.Property == null) { continue; } EndProcessProperty( createdObject, reader, contract, reader.Depth, context.Property, context.Presence.GetValueOrDefault(), !context.Used); } } OnDeserialized(reader, contract, createdObject); return createdObject; }