private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, ConstructorInfo constructorInfo, string id) { ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo"); Type objectType = contract.UnderlyingType; IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndConstructorValues(contract, reader, objectType); IDictionary<ParameterInfo, object> constructorParameters = constructorInfo.GetParameters().ToDictionary(p => p, p => (object)null); IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>(); #if !(UNITY_IPHONE || UNITY_IOS || UNITY_WEBGL || UNITY_XBOXONE || UNITY_XBOX360 || UNITY_PS4 || UNITY_PS3 || UNITY_WII) || (UNITY_IOS || UNITY_WEBGL || UNITY_XBOXONE || UNITY_XBOX360 || UNITY_PS4 || UNITY_PS3 || UNITY_WII && !(UNITY_3_5 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3)) 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); } #else propertyValues.ForEach(propertyValue => { ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.UnderlyingName).Key; if (matchingConstructorParameter != null) constructorParameters[matchingConstructorParameter] = propertyValue.Value; else remainingPropertyValues.Add(propertyValue); }); #endif object createdObject = constructorInfo.Invoke(constructorParameters.Values.ToArray()); if (id != null) Serializer.ReferenceResolver.AddReference(this, id, createdObject); contract.InvokeOnDeserializing(createdObject, Serializer.Context); #if !(UNITY_IPHONE || UNITY_IOS || UNITY_WEBGL || UNITY_XBOXONE || UNITY_XBOX360 || UNITY_PS4 || UNITY_PS3 || UNITY_WII) || (UNITY_IOS || UNITY_WEBGL || UNITY_XBOXONE || UNITY_XBOX360 || UNITY_PS4 || UNITY_PS3 || UNITY_WII && !(UNITY_3_5 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3)) // 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 is JsonArrayContract) { JsonArrayContract propertyArrayContract = propertyContract as JsonArrayContract; 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 is JsonDictionaryContract) { JsonDictionaryContract jsonDictionaryContract = propertyContract as JsonDictionaryContract; 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); } } } } } #else // go through unused values and set the newly created object's properties remainingPropertyValues.ForEach(remainingPropertyValue => { 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 is JsonArrayContract) { JsonArrayContract propertyArrayContract = propertyContract as JsonArrayContract; 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 is JsonDictionaryContract) { JsonDictionaryContract jsonDictionaryContract = propertyContract as JsonDictionaryContract; 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); } } } } }); #endif contract.InvokeOnDeserialized(createdObject, Serializer.Context); return createdObject; }
private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, string id) { contract.InvokeOnDeserializing(newObject, Serializer.Context); Dictionary<JsonProperty, PropertyPresence> propertiesPresence = contract.Properties.ToDictionary(m => m, m => PropertyPresence.None); 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 new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name)); reader.Skip(); continue; } if (!ReadForType(reader, property.PropertyType, property.Converter)) throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); SetPropertyPresence(reader, property, propertiesPresence); SetPropertyValue(property, reader, newObject); } catch (Exception ex) { if (IsErrorHandled(newObject, contract, memberName, ex)) HandleError(reader, initialDepth); else throw; } break; case JsonToken.EndObject: foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence) { JsonProperty property = propertyPresence.Key; PropertyPresence presence = propertyPresence.Value; switch (presence) { case PropertyPresence.None: if (property.Required == Required.AllowNull || property.Required == Required.Always) throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Populate) && property.Writable) property.ValueProvider.SetValue(newObject, EnsureType(property.DefaultValue, CultureInfo.InvariantCulture, property.PropertyType)); break; case PropertyPresence.Null: if (property.Required == Required.Always) throw new JsonSerializationException("Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); break; } } contract.InvokeOnDeserialized(newObject, Serializer.Context); return newObject; case JsonToken.Comment: // ignore break; default: throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType); } } while (reader.Read()); throw new JsonSerializationException("Unexpected end when deserializing object."); }
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id) { object newObject = null; 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 (contract.OverrideConstructor != null) { if (contract.OverrideConstructor.GetParameters().Length > 0) return CreateObjectFromNonDefaultConstructor(reader, contract, contract.OverrideConstructor, id); newObject = contract.OverrideConstructor.Invoke(null); } else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) { newObject = contract.DefaultCreator(); } else if (contract.ParametrizedConstructor != null) { return CreateObjectFromNonDefaultConstructor(reader, contract, contract.ParametrizedConstructor, id); } if (newObject == null) throw new JsonSerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); PopulateObject(newObject, reader, contract, id); return newObject; }
private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) { OnSerializing(writer, contract, value); _serializeStack.Add(value); WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty); int initialDepth = writer.Top; for (int index = 0; index < contract.Properties.Count; index++) { JsonProperty property = contract.Properties[index]; try { object memberValue; JsonContract memberContract; if (!CalculatePropertyValues(writer, value, contract, member, property, out memberContract, out memberValue)) { continue; } property.WritePropertyName(writer); SerializeValue(writer, memberValue, memberContract, property, contract, member); } catch (Exception ex) { if (IsErrorHandled(value, contract, property.PropertyName, null, writer.ContainerPath, ex)) { HandleError(writer, initialDepth); } else { throw; } } } if (contract.ExtensionDataGetter != null) { IEnumerable <KeyValuePair <object, object> > extensionData = contract.ExtensionDataGetter(value); if (extensionData != null) { foreach (KeyValuePair <object, object> e in extensionData) { JsonContract keyContract = GetContractSafe(e.Key); JsonContract valueContract = GetContractSafe(e.Value); bool escape; string propertyName = GetPropertyName(writer, e.Key, keyContract, out escape); if (ShouldWriteReference(e.Value, null, valueContract, contract, member)) { writer.WritePropertyName(propertyName); WriteReference(writer, e.Value); } else { if (!CheckForCircularReference(writer, e.Value, null, valueContract, contract, member)) { continue; } writer.WritePropertyName(propertyName); SerializeValue(writer, e.Value, valueContract, null, contract, member); } } } } writer.WriteEndObject(); _serializeStack.RemoveAt(_serializeStack.Count - 1); OnSerialized(writer, contract, value); }
private IDictionary<JsonProperty, object> ResolvePropertyAndConstructorValues(JsonObjectContract contract, JsonReader reader, Type objectType) { IDictionary<JsonProperty, object> propertyValues = new Dictionary<JsonProperty, object>(); bool exit = false; do { switch (reader.TokenType) { case JsonToken.PropertyName: string memberName = reader.Value.ToString(); // attempt exact case match first // then try match ignoring case JsonProperty property = contract.ConstructorParameters.GetClosestMatchProperty(memberName) ?? contract.Properties.GetClosestMatchProperty(memberName); if (property != null) { if (!ReadForType(reader, property.PropertyType, property.Converter)) throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); if (!property.Ignored) propertyValues[property] = CreateValueProperty(reader, property, null, true, null); else reader.Skip(); } else { if (!reader.Read()) throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); if (Serializer.MissingMemberHandling == MissingMemberHandling.Error) throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name)); reader.Skip(); } break; case JsonToken.Comment: break; case JsonToken.EndObject: exit = true; break; default: throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType); } } while (!exit && reader.Read()); return propertyValues; }
private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContract collectionValueContract) { contract.InvokeOnSerializing(value, Serializer.Context); SerializeStack.Add(value); writer.WriteStartObject(); bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); if (isReference) { writer.WritePropertyName(JsonTypeReflector.IdPropertyName); writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, value)); } if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract)) { WriteTypeProperty(writer, contract.UnderlyingType); } int initialDepth = writer.Top; foreach (JsonProperty property in contract.Properties) { try { if (!property.Ignored && property.Readable && ShouldSerialize(property, value) && IsSpecified(property, value)) { object memberValue = property.ValueProvider.GetValue(value); JsonContract memberContract = GetContractSafe(memberValue); WriteMemberInfoProperty(writer, memberValue, property, memberContract); } } catch (Exception ex) { if (IsErrorHandled(value, contract, property.PropertyName, ex)) HandleError(writer, initialDepth); else throw; } } writer.WriteEndObject(); SerializeStack.RemoveAt(SerializeStack.Count - 1); contract.InvokeOnSerialized(value, Serializer.Context); }
private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) { OnSerializing(writer, contract, value); _serializeStack.Add(value); WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty); int initialDepth = writer.Top; for (int index = 0; index < contract.Properties.Count; index++) { JsonProperty property = contract.Properties[index]; try { object memberValue; JsonContract memberContract; if (!CalculatePropertyValues(writer, value, contract, member, property, out memberContract, out memberValue)) continue; property.WritePropertyName(writer); SerializeValue(writer, memberValue, memberContract, property, contract, member); } catch (Exception ex) { if (IsErrorHandled(value, contract, property.PropertyName, null, writer.ContainerPath, ex)) HandleError(writer, initialDepth); else throw; } } if (contract.ExtensionDataGetter != null) { IEnumerable<KeyValuePair<object, object>> extensionData = contract.ExtensionDataGetter(value); if (extensionData != null) { foreach (KeyValuePair<object, object> e in extensionData) { JsonContract keyContract = GetContractSafe(e.Key); JsonContract valueContract = GetContractSafe(e.Value); bool escape; string propertyName = GetPropertyName(writer, e.Key, keyContract, out escape); if (ShouldWriteReference(e.Value, null, valueContract, contract, member)) { writer.WritePropertyName(propertyName); WriteReference(writer, e.Value); } else { if (!CheckForCircularReference(writer, e.Value, null, valueContract, contract, member)) continue; writer.WritePropertyName(propertyName); SerializeValue(writer, e.Value, valueContract, null, contract, member); } } } } writer.WriteEndObject(); _serializeStack.RemoveAt(_serializeStack.Count - 1); OnSerialized(writer, contract, value); }
private void EndObject(object newObject, JsonReader reader, JsonObjectContract contract, int initialDepth, Dictionary<JsonProperty, PropertyPresence> propertiesPresence) { if (propertiesPresence != null) { foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence) { JsonProperty property = propertyPresence.Key; PropertyPresence presence = propertyPresence.Value; if (presence == PropertyPresence.None || presence == PropertyPresence.Null) { try { Required resolvedRequired = property._required ?? contract.ItemRequired ?? Required.Default; switch (presence) { case PropertyPresence.None: if (resolvedRequired == Required.AllowNull || resolvedRequired == Required.Always) throw JsonSerializationException.Create(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable) property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType)); break; case PropertyPresence.Null: if (resolvedRequired == Required.Always) throw JsonSerializationException.Create(reader, "Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName)); break; } } catch (Exception ex) { if (IsErrorHandled(newObject, contract, property.PropertyName, reader as IJsonLineInfo, reader.Path, ex)) HandleError(reader, true, initialDepth); else throw; } } } } }
private void GenerateObjectSchema(Type type, JsonObjectContract contract) { CurrentSchema.Properties = new Dictionary<string, JsonSchema>(); foreach (JsonProperty property in contract.Properties) { if (!property.Ignored) { bool optional = property.NullValueHandling == NullValueHandling.Ignore || HasFlag(property.DefaultValueHandling.GetValueOrDefault(), DefaultValueHandling.Ignore) || property.ShouldSerialize != null || property.GetIsSpecified != null; JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required, !optional); if (property.DefaultValue != null) propertySchema.Default = JToken.FromObject(property.DefaultValue); CurrentSchema.Properties.Add(property.PropertyName, propertySchema); } } if (type.IsSealed) CurrentSchema.AllowAdditionalProperties = false; }
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 PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id) { OnDeserializing(reader, contract, newObject); // 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) AddReference(reader, id, newObject); int initialDepth = reader.Depth; bool finished = false; 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 (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), 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)); if (!reader.Read()) break; SetExtensionData(contract, member, reader, memberName, newObject); 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); // set extension data if property is ignored or readonly if (!SetPropertyValue(property, propertyConverter, contract, member, reader, newObject)) SetExtensionData(contract, member, reader, memberName, newObject); } catch (Exception ex) { if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex)) HandleError(reader, true, initialDepth); else throw; } } break; case JsonToken.EndObject: finished = true; break; case JsonToken.Comment: // ignore break; default: throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType); } } while (!finished && reader.Read()); if (!finished) ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object."); EndObject(newObject, reader, contract, initialDepth, propertiesPresence); OnDeserialized(reader, contract, newObject); return newObject; }
public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultConstructor) { object newObject = null; if (!objectContract.IsInstantiable) throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType)); if (objectContract.OverrideConstructor != null) { if (objectContract.OverrideConstructor.GetParameters().Length > 0) { createdFromNonDefaultConstructor = true; return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.OverrideConstructor, id); } newObject = objectContract.OverrideConstructor.Invoke(null); } else if (objectContract.DefaultCreator != null && (!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null)) { // use the default constructor if it is... // public // non-public and the user has change constructor handling settings // non-public and there is no other constructor newObject = objectContract.DefaultCreator(); } else if (objectContract.ParametrizedConstructor != null) { createdFromNonDefaultConstructor = true; return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedConstructor, id); } if (newObject == null) throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType)); createdFromNonDefaultConstructor = false; return newObject; }
private IDictionary<JsonProperty, object> ResolvePropertyAndConstructorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType) { IDictionary<JsonProperty, object> propertyValues = new Dictionary<JsonProperty, object>(); bool exit = false; do { switch (reader.TokenType) { case JsonToken.PropertyName: string memberName = reader.Value.ToString(); // attempt exact case match first // then try match ignoring case JsonProperty property = contract.ConstructorParameters.GetClosestMatchProperty(memberName) ?? contract.Properties.GetClosestMatchProperty(memberName); if (property != null) { if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, containerProperty); if (!ReadForType(reader, property.PropertyContract, propertyConverter != null)) throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); if (!property.Ignored) { if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); object propertyValue; if (propertyConverter != null && propertyConverter.CanRead) propertyValue = DeserializeConvertable(propertyConverter, reader, property.PropertyType, null); else propertyValue = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null); propertyValues[property] = propertyValue; } else { reader.Skip(); } } else { if (!reader.Read()) throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}.".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null); if (Serializer._missingMemberHandling == MissingMemberHandling.Error) throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name)); reader.Skip(); } break; case JsonToken.Comment: break; case JsonToken.EndObject: exit = true; break; default: throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType); } } while (!exit && reader.Read()); return propertyValues; }
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, string id) { ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo"); // 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) 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); 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); if (propertiesPresence != null) { // map from constructor 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 = constructorInfo.Invoke(constructorParameters.Values.ToArray()); 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(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 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); } } } } } EndObject(createdObject, reader, contract, reader.Depth, propertiesPresence); OnDeserialized(reader, contract, createdObject); return createdObject; }