private void DeserializeDictionaryGeneric <TValue>(IDeserializerNode node, Reader reader, DictionaryTypeSpec dictType) { IDictionary <string, TValue> dict; if (node.Value != null) { dict = (IDictionary <string, TValue>)node.Value; } else { dict = new Dictionary <string, TValue>(); } var jobj = reader.Token as JObject; var valueType = dictType.ValueType; if (jobj == null) { throw new PomonaSerializationException( "Expected dictionary property to have a JSON object value, but was " + reader.Token.Type); } foreach (var jprop in jobj.Properties()) { var jpropName = jprop.Name; if (jpropName.Length > 0 && reservedFirstCharacters.Contains(jpropName[0])) { if (jpropName[0] == '-') { // Removal operation var unescapedPropertyName = UnescapePropertyName(jpropName.Substring(1)); dict.Remove(unescapedPropertyName); } else { throw new PomonaSerializationException( "Unexpected character in json property name. Have propertie names been correctly escaped?"); } } else { var unescapedPropertyName = UnescapePropertyName(jpropName); var itemNode = new ItemValueDeserializerNode(valueType, node.Context, node.ExpandPath + "." + unescapedPropertyName); DeserializeThroughContext(itemNode, new Reader(jprop.Value)); dict[unescapedPropertyName] = (TValue)itemNode.Value; } } if (node.Value == null) { node.Value = dict; } }
private object Deserialize(TextReader textReader, TypeSpec expectedBaseType, IDeserializationContext context, object patchedObject) { var node = new ItemValueDeserializerNode(expectedBaseType, context); node.Operation = patchedObject != null ? DeserializerNodeOperation.Patch : DeserializerNodeOperation.Post; if (patchedObject != null) { node.Value = patchedObject; } var reader = CreateReader(textReader); DeserializeThroughContext(node, reader); return(node.Value); }
private void DeserializeArrayNodeGeneric <TElement>(IDeserializerNode node, Reader reader) { if (TryDeserializeAsReference(node, reader)) { return; } var jarr = reader.Token as JArray; if (jarr == null) { throw new PomonaSerializationException("Expected JSON token of type array, but was " + reader.Token.Type); } var expectedBaseType = node.ExpectedBaseType; // Deserialize as object array by default bool asArray; TypeSpec elementType; if (expectedBaseType != null && expectedBaseType.IsCollection) { elementType = expectedBaseType.ElementType; asArray = expectedBaseType.IsArray; } else { elementType = node.Context.GetClassMapping(typeof(object)); asArray = true; } bool isPatching; ICollection <TElement> collection; if (node.Value == null) { if (expectedBaseType != null && expectedBaseType == typeof(ISet <TElement>)) { collection = new HashSet <TElement>(); } else { collection = new List <TElement>(); } isPatching = false; } else { collection = (ICollection <TElement>)node.Value; isPatching = true; } if (isPatching && node.Operation == DeserializerNodeOperation.Post) { // Clear list and add new items node.CheckItemAccessRights(HttpMethod.Delete); collection.Clear(); } foreach (var jitem in jarr) { var jobj = jitem as JObject; var itemNode = new ItemValueDeserializerNode(elementType, node.Context, node.ExpandPath, node); if (jobj != null) { foreach (var jprop in jobj.Properties().Where(IsIdentifierProperty)) { // Starts with "-@" or "*@" var identifyPropName = jprop.Name.Substring(2); var identifyProp = itemNode.ValueType.Properties.FirstOrDefault(x => x.JsonName == identifyPropName); if (identifyProp == null) { throw new PomonaSerializationException("Unable to find predicate property " + jprop.Name + " in object"); } var identifierNode = new ItemValueDeserializerNode(identifyProp.PropertyType, itemNode.Context, parent: itemNode); DeserializeThroughContext(identifierNode, new Reader(jprop.Value)); var identifierValue = identifierNode.Value; if (jprop.Name[0] == '-') { itemNode.Operation = DeserializerNodeOperation.Delete; } else if (jprop.Name[0] == '*') { itemNode.Operation = DeserializerNodeOperation.Patch; } else { throw new PomonaSerializationException("Unexpected json patch identifier property."); } itemNode.Value = collection.Cast <object>().First( x => identifierValue.Equals(identifyProp.GetValue(x, itemNode.Context))); } } if (itemNode.Operation == DeserializerNodeOperation.Delete) { node.CheckItemAccessRights(HttpMethod.Delete); collection.Remove((TElement)itemNode.Value); } else { if (itemNode.Operation == DeserializerNodeOperation.Patch) { node.CheckItemAccessRights(HttpMethod.Patch); } else if (isPatching) { node.CheckAccessRights(HttpMethod.Post); } DeserializeThroughContext(itemNode, new Reader(jitem)); if (itemNode.Operation != DeserializerNodeOperation.Patch) { if (!(itemNode.ExpectedBaseType is StructuredType) || itemNode.ExpectedBaseType.IsAnonymous() || !collection.Contains((TElement)itemNode.Value)) { collection.Add((TElement)itemNode.Value); } } } } if (node.Value == null) { node.Value = asArray ? collection.ToArray() : collection; } }