Пример #1
0
        /// <summary>
        /// Find the item in SpecificationData whose properties best match the given .NET type.
        /// </summary>
        private RuntimeTypeData FindBestMatchingSpecification(Type netType)
        {
            RuntimeTypeData bestMatch = null;
            int             bestMatchingPropertiesCount = 0;
            Dictionary <string, System.Reflection.PropertyInfo> netProperties = new Dictionary <string, System.Reflection.PropertyInfo>();

            foreach (System.Reflection.PropertyInfo pi in netType.GetProperties())
            {
                netProperties[pi.Name.ToLowerInvariant()] = pi;
            }

            foreach (RuntimeTypeData candidate in this.SpecificationData)
            {
                int matchingProperties = 0;
                foreach (string propertyName in candidate.Properties.Keys)
                {
                    if (netProperties.ContainsKey(propertyName) && (candidate.Properties[propertyName].Type == null || candidate.Properties[propertyName].Type.Type == null || candidate.Properties[propertyName].Type.Type.Equals(netProperties[propertyName].PropertyType)))
                    {
                        matchingProperties++;
                    }
                }

                if (bestMatch == null || bestMatchingPropertiesCount < matchingProperties)
                {
                    bestMatchingPropertiesCount = matchingProperties;
                    bestMatch = candidate;
                }
            }

            return(bestMatch);
        }
Пример #2
0
        /// <summary>
        /// Complete creation of this response type by merging all sources of data.
        /// </summary>
        public void Complete()
        {
            this.TypeData = this.ModuleData;
            RuntimeTypeData specificationData = FindBestMatchingSpecification(this.ModuleData.Type);

            if (specificationData != null)
            {
                this.TypeData.MergeWith(specificationData);
            }
        }
Пример #3
0
        public RuntimeTypeData Clone()
        {
            RuntimeTypeData data = new RuntimeTypeData();

            data.Type = this.Type;
            foreach (RuntimeTypeData d in this.CollectionTypes)
            {
                data.CollectionTypes.Add(d.Clone());
            }

            foreach (string key in this.Properties.Keys)
            {
                data.Properties[key] = this.Properties[key].Clone();
            }

            return(data);
        }
Пример #4
0
        public void MergeWith(RuntimeTypeData newData)
        {
            if (newData.Type != null)
            {
                this.Type = newData.Type;
            }

            if (newData.CollectionTypes != null)
            {
                this.CollectionTypes = newData.CollectionTypes;
            }

            if (newData.Properties != null)
            {
                this.Properties = newData.Properties;
            }
        }
Пример #5
0
        private void CompleteRuntimeDataType(RuntimeTypeData data)
        {
            // At this point, data should have its Type filled in. In case it isn't, let's let an exception bubble up as an error
            Type netType = data.Type;
            Dictionary <string, Type> propertyTypes = new Dictionary <string, Type>();

            foreach (PropertyInfo pi in netType.GetProperties())
            {
                propertyTypes[pi.Name.ToLowerInvariant()] = pi.PropertyType;
            }

            foreach (string propertyName in data.Properties.Keys)
            {
                ParameterData propertyData = data.Properties[propertyName];
                if (propertyData.Type != null)
                {
                    // Sometimes the Name property isn't set - propertyName is correct in this case
                    if (String.IsNullOrEmpty(propertyData.Name))
                    {
                        propertyData.Name = propertyName;
                    }

                    RuntimeTypeData propertyTypeData = propertyData.Type;
                    if (propertyTypeData.Type == null)
                    {
                        // Find the type of this property
                        if (propertyTypes.ContainsKey(propertyName))
                        {
                            propertyTypeData.Type = propertyTypes[propertyName];
                            // Recursively fill in the properties of this type
                            CompleteRuntimeDataType(propertyTypeData);
                        }
                    }
                }
            }
        }
Пример #6
0
        private RuntimeTypeData GetRuntimeTypeDataFromDefinition(string definitionName, JsonPathFinder definitionNode, Dictionary <string, RuntimeTypeData> cache, JsonPathFinder rootDoc)
        {
            // 0. Check if the type already exists
            if (cache.ContainsKey(definitionName))
            {
                return(cache[definitionName]);
            }

            RuntimeTypeData data = new RuntimeTypeData();

            cache[definitionName] = data;
            // 1. Get properties node
            JsonPathFinder propertiesNode = definitionNode.Find(new JsonQueryBuilder().Property("properties")).SingleOrDefault();

            if (propertiesNode != null)
            {
                // 2. Read flat properties
                foreach (JsonPathFinder propertyContainerNode in propertiesNode.Children())
                {
                    JsonPathFinder propertyNode = propertyContainerNode.OpenContainer();
                    // First things first - check if the property is renamed
                    JsonPathFinder clientNameNode = propertyNode.Find(new JsonQueryBuilder().Property("x-ms-client-name")).SingleOrDefault();
                    string         clientName     = String.Empty;
                    if (clientNameNode != null)
                    {
                        clientName = clientNameNode.GetValue <string>().ToLowerInvariant();
                    }

                    string jsonName    = propertyNode.Key.ToLowerInvariant();
                    string rawJsonName = propertyNode.Key;
                    // 5 cases:
                    //  1: Property contains a $ref node AND property contains an x-ms-client-flatten node
                    //  2: Property contains only a $ref node
                    //  3: Property is of type object and contains additionalProperties (not sure how to handle this yet)
                    //  4: Property is of type array (decode the individual items type)
                    //  5: Property is a simple property
                    JsonPathFinder refNode     = propertyNode.Find(new JsonQueryBuilder().Property("$ref")).SingleOrDefault();
                    JsonPathFinder flattenNode = propertyNode.Find(new JsonQueryBuilder().Property("x-ms-client-flatten")).SingleOrDefault();
                    JsonPathFinder typeNode    = propertyNode.Find(new JsonQueryBuilder().Property("type")).SingleOrDefault();
                    JsonPathFinder additionalPropertiesNode = propertyNode.Find(new JsonQueryBuilder().Property("additionalProperties")).SingleOrDefault();
                    JsonPathFinder arrayItemsRefNode        = propertyNode.Find(new JsonQueryBuilder().Property("items").Property("$ref")).SingleOrDefault();
                    JsonPathFinder propertiesSubNode        = propertyNode.Find(new JsonQueryBuilder().Property("properties")).SingleOrDefault();
                    if (refNode != null)
                    {
                        JsonPathFinder  subDefinition      = rootDoc.Find(new JsonQueryBuilder(refNode.GetValue <string>())).Single();
                        RuntimeTypeData referencedTypeData = GetRuntimeTypeDataFromDefinition(subDefinition.Path, subDefinition, cache, rootDoc);
                        if (flattenNode != null && flattenNode.GetValue <bool>())
                        {
                            // Push the properties of the referenced type to this type
                            // If it's flattened, the jsonName should actually be flatJsonName
                            foreach (string propertyName in referencedTypeData.Properties.Keys)
                            {
                                data.Properties[propertyName]             = referencedTypeData.Properties[propertyName].Clone();
                                data.Properties[propertyName].SubNodeName = "properties";
                            }
                        }
                        else
                        {
                            // The referenced type is simply the type of this property
                            data.Properties[jsonName] = new ParameterData()
                            {
                                Name        = clientName,
                                JsonName    = jsonName,
                                RawJsonName = rawJsonName,
                                Type        = referencedTypeData
                            };
                        }
                    }
                    else if (typeNode != null && typeNode.GetValue <string>().ToLowerInvariant().Equals("object") && additionalPropertiesNode != null)
                    {
                        // No converter required, this will probably be a Dictionary<string, something>
                        data.Properties[jsonName] = new ParameterData()
                        {
                            Name        = clientName,
                            JsonName    = jsonName,
                            RawJsonName = rawJsonName
                        };

                        // TODO: Support complex object as the additionalProperties type. Don't have a good example if this yet...
                    }
                    else if (typeNode != null && typeNode.GetValue <string>().ToLowerInvariant().Equals("array"))
                    {
                        // No converter required
                        data.Properties[jsonName] = new ParameterData()
                        {
                            Name        = clientName,
                            JsonName    = jsonName,
                            RawJsonName = rawJsonName
                        };

                        // When this is an array, we should add the type of the items in the array so that a converter is registered later
                        if (arrayItemsRefNode != null)
                        {
                            JsonPathFinder subDefinition = rootDoc.Find(new JsonQueryBuilder(arrayItemsRefNode.GetValue <string>())).Single();
                            data.Properties[jsonName].Type = new RuntimeTypeData();
                            data.Properties[jsonName].Type.CollectionTypes.Add(GetRuntimeTypeDataFromDefinition(subDefinition.Path, subDefinition, cache, rootDoc));
                        }
                    }
                    else if (propertiesSubNode != null)
                    {
                        // Not sure what to do with definition name yet
                        // The actual Type of the anonymous type will be filled in by postprocessing
                        // TODO: The properties of the subtype might be prefixed with "properties."
                        data.Properties[jsonName] = new ParameterData()
                        {
                            Name        = clientName,
                            JsonName    = jsonName,
                            RawJsonName = rawJsonName,
                            Type        = GetRuntimeTypeDataFromDefinition(Guid.NewGuid().ToString(), propertyNode, cache, rootDoc)
                        };
                    }
                    else
                    {
                        // The last case should be the case of a simple property - assign the name and jsonName and let the type be inferred later
                        data.Properties[jsonName] = new ParameterData()
                        {
                            Name        = clientName,
                            JsonName    = jsonName,
                            RawJsonName = rawJsonName,
                            Type        = new RuntimeTypeData()
                        };
                    }
                }
            }

            // 3. Read allOf node
            JsonPathFinder allOfNode = definitionNode.Find(new JsonQueryBuilder().Property("allOf")).SingleOrDefault();

            if (allOfNode != null)
            {
                // Get all $ref's
                foreach (JsonPathFinder refNode in allOfNode.Find(new JsonQueryBuilder().RecursiveDescent().Property("$ref")))
                {
                    JsonPathFinder  subDefinition      = rootDoc.Find(new JsonQueryBuilder(refNode.GetValue <string>())).Single();
                    RuntimeTypeData referencedTypeData = GetRuntimeTypeDataFromDefinition(subDefinition.Path, subDefinition, cache, rootDoc);
                    // Push the properties of the referenced type to this type
                    foreach (string propertyName in referencedTypeData.Properties.Keys)
                    {
                        data.Properties[propertyName] = referencedTypeData.Properties[propertyName];
                    }
                }
            }

            return(data);
        }
Пример #7
0
        private Dictionary <string, ParameterData> GetParameterMetadata(string parameterPath, JsonPathFinder parameter, Dictionary <string, RuntimeTypeData> definitionsCache, Dictionary <string, Dictionary <string, ParameterData> > parameterCache, JsonPathFinder rootDoc)
        {
            if (parameterCache.ContainsKey(parameterPath))
            {
                // We've already transformed this parameter into one or more parameters and found the correct module name
                return(parameterCache[parameterPath]);
            }

            Dictionary <string, ParameterData> ret = new Dictionary <string, ParameterData>();

            parameterCache[parameterPath] = ret;
            // 1. Check if it's a ref
            JsonPathFinder refNode = parameter.Find(new JsonQueryBuilder().Property("$ref")).SingleOrDefault();

            if (refNode != null)
            {
                // A direct ref should reference a parameter object
                string refParameterPath = refNode.GetValue <string>();
                return(GetParameterMetadata(refParameterPath.ToLowerInvariant(), rootDoc.Find(new JsonQueryBuilder(refParameterPath)).Single(), definitionsCache, parameterCache, rootDoc));
            }
            else
            {
                // 2. Get the name and jsonName
                string         jsonName       = String.Empty;
                string         clientName     = String.Empty;
                JsonPathFinder jsonNameNode   = parameter.Find(new JsonQueryBuilder().Property("name")).SingleOrDefault();
                JsonPathFinder clientNameNode = parameter.Find(new JsonQueryBuilder().Property("x-ms-client-name")).SingleOrDefault();
                if (jsonNameNode != null)
                {
                    jsonName = jsonNameNode.GetValue <string>().ToLowerInvariant();
                }

                if (clientNameNode != null)
                {
                    clientName = clientNameNode.GetValue <string>().ToLowerInvariant();
                }

                // 2. Check if it's a flatten
                JsonPathFinder flattenNode   = parameter.Find(new JsonQueryBuilder().Property("x-ms-client-flatten")).SingleOrDefault();
                JsonPathFinder schemaRefNode = parameter.Find(new JsonQueryBuilder().RecursiveDescent().Property("$ref")).SingleOrDefault();
                if (flattenNode != null)
                {
                    // Get the ref node under the schema node - using recursive descent from the parameter node should work
                    // This should be a definitions object
                    string          definitionPath = schemaRefNode.GetValue <string>();
                    RuntimeTypeData definitionData = definitionsCache[definitionPath];
                    // Don't think there will be a flatten of an object that's just an array?
                    foreach (string propertyName in definitionData.Properties.Keys)
                    {
                        ParameterData data = definitionData.Properties[propertyName];
                        if (!String.IsNullOrEmpty(data.Name))
                        {
                            ret[data.Name] = data;
                        }
                        else
                        {
                            ret[data.JsonName] = data;
                        }
                    }
                }
                else
                {
                    // 3. Just a regular parameter - check if it defines a definition as the type
                    ParameterData data = new ParameterData();
                    data.Name     = clientName;
                    data.JsonName = jsonName;
                    if (schemaRefNode != null)
                    {
                        string definitionPath = schemaRefNode.GetValue <string>().ToLowerInvariant();
                        data.Type = definitionsCache[definitionPath];
                    }
                    else
                    {
                        // Type with no properties, and the Type itself will be filled in later
                        data.Type = new RuntimeTypeData();
                    }

                    if (!String.IsNullOrEmpty(clientName))
                    {
                        ret[clientName] = data;
                    }
                    else
                    {
                        ret[jsonName] = data;
                    }
                }
            }

            return(ret);
        }