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(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)) { 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 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 || property.DefaultValueHandling == DefaultValueHandling.Ignore || property.ShouldSerialize != 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 object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, string id) { Type objectType = contract.UnderlyingType; if (contract.ParametrizedConstructor == null) throw new JsonSerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor or only one constructor with arguments.".FormatWith(CultureInfo.InvariantCulture, objectType)); // create a dictionary to put retrieved values into IDictionary<JsonProperty, object> propertyValues = contract.Properties.Where(p => !p.Ignored).ToDictionary(kv => kv, kv => (object)null); bool exit = false; do { switch (reader.TokenType) { case JsonToken.PropertyName: string memberName = reader.Value.ToString(); if (!reader.Read()) throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); // attempt exact case match first // then try match ignoring case JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName); if (property != null) { if (!property.Ignored) propertyValues[property] = CreateValueProperty(reader, property, null, true, null); else reader.Skip(); } else { 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.EndObject: exit = true; break; default: throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType); } } while (!exit && reader.Read()); IDictionary<ParameterInfo, object> constructorParameters = contract.ParametrizedConstructor.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.PropertyName).Key; if (matchingConstructorParameter != null) constructorParameters[matchingConstructorParameter] = propertyValue.Value; else remainingPropertyValues.Add(propertyValue); } object createdObject = contract.ParametrizedConstructor.Invoke(constructorParameters.Values.ToArray()); if (id != null) Serializer.ReferenceResolver.AddReference(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); } 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, RequiredValue> requiredProperties = contract.Properties.Where(m => m.Required != Required.Default).ToDictionary(m => m, m => RequiredValue.None); if (id != null) Serializer.ReferenceResolver.AddReference(id, newObject); int initialDepth = reader.Depth; 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.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 (property.PropertyType == typeof(byte[])) { reader.ReadAsBytes(); } else { if (!reader.Read()) throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); } SetRequiredProperty(reader, property, requiredProperties); try { 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, RequiredValue> requiredProperty in requiredProperties) { if (requiredProperty.Value == RequiredValue.None) throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName)); if (requiredProperty.Key.Required == Required.Always && requiredProperty.Value == RequiredValue.Null) throw new JsonSerializationException("Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName)); } 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.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) { newObject = contract.DefaultCreator(); } if (newObject != null) { PopulateObject(newObject, reader, contract, id); return newObject; } return CreateObjectFromNonDefaultConstructor(reader, contract, id); }