コード例 #1
0
 public void SetProperty(IDeserializerNode targetNode, PropertySpec property, object propertyValue)
 {
     if (targetNode.Operation == DeserializerNodeOperation.Default)
     {
         throw new InvalidOperationException("Invalid deserializer node operation default");
     }
     if ((targetNode.Operation == DeserializerNodeOperation.Post &&
          property.AccessMode.HasFlag(HttpMethod.Post)) ||
         (targetNode.Operation == DeserializerNodeOperation.Patch &&
          property.AccessMode.HasFlag(HttpMethod.Put)))
     {
         property.SetValue(targetNode.Value, propertyValue, targetNode.Context);
     }
     else
     {
         var propPath = string.IsNullOrEmpty(targetNode.ExpandPath)
             ? property.Name
             : targetNode.ExpandPath + "." + property.Name;
         throw new ResourceValidationException(
                   $"Property {property.Name} of resource {targetNode.ValueType.Name} is not writable.",
                   propPath,
                   targetNode.ValueType.Name,
                   null);
     }
 }
コード例 #2
0
 public PropertyValueDeserializerNode(IDeserializerNode parent, PropertySpec property)
 {
     Parent = parent;
     Property = property;
     ValueType = property.PropertyType;
     Context = parent.Context;
 }
コード例 #3
0
 public PropertyValueDeserializerNode(IDeserializerNode parent, PropertySpec property)
 {
     this.parent = parent;
     this.property = property;
     this.valueType = property.PropertyType;
     this.context = parent.Context;
 }
コード例 #4
0
        public object CreateReference(IDeserializerNode node)
        {
            var uri  = node.Uri;
            var type = node.ValueType;

            /*
             * if (type.Type.IsGenericType && type.Type.GetGenericTypeDefinition() == typeof(ClientRepository<,>))
             * {
             *  if (node.Parent != null)
             *  {
             *      var childRepositoryType =
             *          typeof(ChildResourceRepository<,>).MakeGenericType(type.Type.GetGenericArguments());
             *      return Activator.CreateInstance(childRepositoryType, client, uri, null, node.Parent.Value);
             *  }
             *  return Activator.CreateInstance(type.Type, client, uri, null);
             * }*/

            if (type.SerializationMode == TypeSerializationMode.Array)
            {
                return(LazyCollectionProxy.CreateForType(type, uri, this.client));
            }

            if (type is StructuredType && type.SerializationMode == TypeSerializationMode.Structured)
            {
                var clientType = (StructuredType)type;
                var proxyType  = clientType.ResourceInfo.LazyProxyType;
                var refobj     = (LazyProxyBase)Activator.CreateInstance(proxyType);
                refobj.Initialize(uri, this.resourceLoader, clientType.ResourceInfo.PocoType, node.ExpandPath);
                return(refobj);
            }

            throw new NotImplementedException("Don't know how to make reference to type " + type.Name + " yet!");
        }
コード例 #5
0
        private void DeserializeDictionary(IDeserializerNode node, Reader reader)
        {
            if (TryDeserializeAsReference(node, reader))
            {
                return;
            }
            var dictType = node.ExpectedBaseType as DictionaryTypeSpec;

            if (dictType == null)
            {
                dictType = (DictionaryTypeSpec)node.Context.GetClassMapping(typeof(Dictionary <string, object>));
            }

            var keyType = dictType.KeyType.Type;

            if (keyType != typeof(string))
            {
                throw new NotImplementedException(
                          "Only supports deserialization to IDictionary<TKey,TValue> where TKey is of type string.");
            }

            var valueType = dictType.ValueType.Type;

            deserializeDictionaryGenericMethod(valueType, this, node, reader, dictType);
        }
コード例 #6
0
        private void DeserializeComplexNode(IDeserializerNode node, Reader reader)
        {
            if (TryDeserializeAsReference(node, reader))
            {
                return;
            }

            var jobj = reader.Token as JObject;

            if (jobj == null)
            {
                throw new PomonaSerializationException(
                          "Trying to deserialize to complex type, expected a JSON object type but got " + reader.Token.Type);
            }

            SetNodeValueType(node, jobj);

            if (node.Operation == DeserializerNodeOperation.Default)
            {
                node.Operation = node.Value == null ? DeserializerNodeOperation.Post : DeserializerNodeOperation.Patch;
            }

            var propertyValueSource = new PropertyValueSource(jobj, node, this);

            propertyValueSource.Deserialize();
        }
コード例 #7
0
        private static bool TryDeserializeAsReference(IDeserializerNode node, Reader reader)
        {
            var jobj = reader.Token as JObject;

            if (jobj == null)
            {
                return(false);
            }

            SetNodeValueType(node, jobj);

            JToken refStringToken;

            if (!jobj.TryGetValue("_ref", out refStringToken) || refStringToken.Type != JTokenType.String)
            {
                return(false);
            }

            var refString = (string)((JValue)refStringToken).Value;

            node.Uri = refString;

            try
            {
                node.Value = node.Context.CreateReference(node);
            }
            catch (Exception ex)
            {
                throw new PomonaSerializationException("Failed to deserialize: " + ex.Message, ex);
            }
            return(true);
        }
コード例 #8
0
 public PropertyValueDeserializerNode(IDeserializerNode parent, PropertySpec property)
 {
     Parent    = parent;
     Property  = property;
     ValueType = property.PropertyType;
     Context   = parent.Context;
 }
コード例 #9
0
 public void OnMissingRequiredPropertyError(IDeserializerNode node, PropertySpec targetProp)
 {
     throw new ResourceValidationException(
               $"Property {targetProp.Name} is required when creating resource {node.ValueType.Name}",
               targetProp.Name,
               node.ValueType.Name,
               null);
 }
コード例 #10
0
 public PropertyValueSource(JObject jobj, IDeserializerNode node, PomonaJsonDeserializer deserializer)
 {
     this.node         = node;
     this.deserializer = deserializer;
     this.propertyDict = jobj.Properties()
                         .Select(x => new PropertyContainer(x))
                         .ToDictionary(x => x.Name, x => x, StringComparer.InvariantCultureIgnoreCase);
 }
コード例 #11
0
        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;
            }
        }
コード例 #12
0
 public ItemValueDeserializerNode(TypeSpec expectedBaseType, IDeserializationContext context,
                                  string expandPath = "", IDeserializerNode parent = null)
 {
     this.parent = parent;
     this.expectedBaseType = expectedBaseType;
     this.context = context;
     this.expandPath = expandPath;
     valueType = expectedBaseType;
 }
コード例 #13
0
 public ItemValueDeserializerNode(TypeSpec expectedBaseType,
                                  IDeserializationContext context,
                                  string expandPath        = "",
                                  IDeserializerNode parent = null)
 {
     Parent           = parent;
     ExpectedBaseType = expectedBaseType;
     Context          = context;
     ExpandPath       = expandPath;
     this.valueType   = expectedBaseType;
 }
コード例 #14
0
        public void Deserialize(IDeserializerNode node, Action <IDeserializerNode> nodeDeserializeAction)
        {
            nodeDeserializeAction(node);

            var transformedType = node.ValueType as StructuredType;

            if (transformedType != null && transformedType.OnDeserialized != null && node.Value != null)
            {
                transformedType.OnDeserialized(node.Value);
            }
        }
コード例 #15
0
 public void Deserialize(IDeserializerNode node, Action <IDeserializerNode> deserializeNodeAction)
 {
     deserializeNodeAction(node);
     if (node.Uri != null)
     {
         var uriResource = node.Value as IHasSettableResourceUri;
         if (uriResource != null)
         {
             uriResource.Uri = node.Uri;
         }
     }
 }
コード例 #16
0
        public void SetProperty(IDeserializerNode target, PropertySpec property, object propertyValue)
        {
            if (!property.IsWritable)
            {
                throw new InvalidOperationException("Unable to set property.");
            }

            if (typeof(IClientRepository).IsAssignableFrom(property.PropertyType))
            {
                var repoImplementationType = this.clientRepositoryImplementationMap.GetOrAdd(property.PropertyType,
                                                                                             t =>
                                                                                             t.Assembly.GetTypes()
                                                                                             .First(
                                                                                                 x =>
                                                                                                 !x.IsInterface &&
                                                                                                 x.IsClass &&
                                                                                                 t
                                                                                                 .IsAssignableFrom
                                                                                                     (x)));

                var    listProxyValue = propertyValue as LazyCollectionProxy;
                object repo;
                if (listProxyValue != null)
                {
                    repo = Activator.CreateInstance(repoImplementationType,
                                                    this.client,
                                                    listProxyValue.Uri,
                                                    null,
                                                    target.Value);
                }
                else
                {
                    repo = Activator.CreateInstance(repoImplementationType,
                                                    this.client,
                                                    target.Uri + "/" + NameUtils.ConvertCamelCaseToUri(property.Name),
                                                    propertyValue,
                                                    target.Value);
                }
                property.SetValue(target.Value, repo);
                return;
            }

            property.SetValue(target.Value, propertyValue);
        }
コード例 #17
0
        private void DeserializeArrayNode(IDeserializerNode node, Reader reader)
        {
            if (TryDeserializeAsReference(node, reader))
            {
                return;
            }

            TypeSpec elementType;

            if (node.ExpectedBaseType != null && node.ExpectedBaseType.IsCollection)
            {
                elementType = node.ExpectedBaseType.ElementType;
            }
            else
            {
                elementType = node.Context.GetClassMapping(typeof(object));
            }

            deserializeArrayNodeGenericMethod(elementType, this, node, reader);
        }
コード例 #18
0
        private void DeserializeValueNode(IDeserializerNode node, Reader reader)
        {
            if (reader.Token.Type == JTokenType.Object)
            {
                var    jobj = reader.Token as JObject;
                JToken typeNameToken;
                if (!jobj.TryGetValue("_type", out typeNameToken))
                {
                    throw new PomonaSerializationException(
                              "Trying to deserialize boxed value, but lacks _type property.");
                }

                JToken valueToken;
                if (!jobj.TryGetValue("value", out valueToken))
                {
                    throw new PomonaSerializationException(
                              "Trying to deserialize boxed value, but lacks value property.");
                }

                var typeName = typeNameToken.ToString();
                node.SetValueType(typeName);
                node.Value = valueToken.ToObject(node.ValueType.Type, this.jsonSerializer);
            }
            else
            {
                var converter = node.ValueType.GetCustomJsonConverter();
                if (converter == null)
                {
                    node.Value = reader.Token.ToObject(node.ValueType.Type, this.jsonSerializer);
                }
                else
                {
                    node.Value = converter.ReadJson(new JTokenReader(reader.Token),
                                                    node.ValueType.Type,
                                                    null,
                                                    this.jsonSerializer);
                }
            }
        }
コード例 #19
0
 public void OnMissingRequiredPropertyError(IDeserializerNode node, PropertySpec targetProp)
 {
 }
コード例 #20
0
        private void DeserializeNode(IDeserializerNode node, Reader reader)
        {
            if (reader.Token.Type == JTokenType.Null)
            {
                if (node.ExpectedBaseType != null && node.ExpectedBaseType.Type.IsValueType && !node.ExpectedBaseType.IsNullable)
                {
                    throw new PomonaSerializationException("Deserialized to null, which is not allowed value for casting to type "
                                                           + node.ValueType.FullName);
                }
                node.Value = null;
                return;
            }

            TypeSpec mappedType;

            if (node.ExpectedBaseType != null && node.ExpectedBaseType != typeof(object))
            {
                if (SetNodeValueType(node, reader.Token))
                {
                    mappedType = node.ValueType;
                }
                else
                {
                    mappedType = node.ExpectedBaseType;
                }
            }
            else if (reader.Token.Type == JTokenType.String)
            {
                node.SetValueType(node.Context.GetClassMapping(typeof(string)));
                mappedType = node.ValueType;
            }
            else
            {
                if (!SetNodeValueType(node, reader.Token))
                {
                    throw new PomonaSerializationException(
                              "No expected type to deserialize to provided, and unable to get type from incoming JSON.");
                }
                mappedType = node.ValueType;
            }

            switch (mappedType.SerializationMode)
            {
            case TypeSerializationMode.Structured:
                DeserializeComplexNode(node, reader);
                break;

            case TypeSerializationMode.Value:
                DeserializeValueNode(node, reader);
                break;

            case TypeSerializationMode.Array:
                DeserializeArrayNode(node, reader);
                break;

            case TypeSerializationMode.Dictionary:
                DeserializeDictionary(node, reader);
                break;

            default:
                throw new NotImplementedException("Don't know how to deserialize node with mode " +
                                                  mappedType.SerializationMode);
            }
        }
コード例 #21
0
 private void DeserializeThroughContext(IDeserializerNode node, Reader reader)
 {
     node.Context.Deserialize(node, n => DeserializeNode(n, reader));
 }
コード例 #22
0
 public object CreateReference(IDeserializerNode node)
 {
     return(this.resourceResolver.ResolveUri(node.Uri));
 }
コード例 #23
0
        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;
            }
        }
コード例 #24
0
        private static bool SetNodeValueType(IDeserializerNode node, JToken jtoken)
        {
            var jobj = jtoken as JObject;

            if (jobj != null)
            {
                JToken explicitTypeSpec;
                if (jobj.TryGetValue("_type", out explicitTypeSpec))
                {
                    if (explicitTypeSpec.Type != JTokenType.String)
                    {
                        throw new PomonaSerializationException(
                                  "Found _type property on JSON object and expected this to be string, but got " +
                                  explicitTypeSpec.Type);
                    }

                    var typeName = explicitTypeSpec.Value <string>();
                    if (typeName == "__result__")
                    {
                        if (!(node.ExpectedBaseType is QueryResultType) && node.ExpectedBaseType is EnumerableTypeSpec)
                        {
                            Type queryResultGenericTypeDefinition;
                            if (node.ExpectedBaseType.Type.IsGenericInstanceOf(typeof(ISet <>)))
                            {
                                queryResultGenericTypeDefinition = typeof(QuerySetResult <>);
                            }
                            else
                            {
                                queryResultGenericTypeDefinition = typeof(QueryResult <>);
                            }
                            var queryResultTypeInstance = queryResultGenericTypeDefinition.MakeGenericType(node.ExpectedBaseType.ElementType);
                            if (node.ExpectedBaseType.Type.IsAssignableFrom(queryResultTypeInstance))
                            {
                                node.SetValueType(queryResultTypeInstance);
                            }
                        }
                    }
                    else
                    {
                        node.SetValueType(typeName);
                    }
                    return(true);
                }
            }

            if (node.ExpectedBaseType == null || node.ExpectedBaseType == typeof(object))
            {
                switch (jtoken.Type)
                {
                case JTokenType.String:
                    node.SetValueType(typeof(string));
                    return(true);

                case JTokenType.Boolean:
                    node.SetValueType(typeof(bool));
                    return(true);

                case JTokenType.Array:
                    node.SetValueType(typeof(object[]));
                    return(true);

                case JTokenType.Object:
                    node.SetValueType(typeof(Dictionary <string, object>));
                    return(true);

                default:
                    return(false);
                }
            }

            return(false);
        }