Exemplo n.º 1
0
        static CodeBlock WriteNode(
            Variable <JsonWriter> jsonWriter,
            TypedExpression <string> baseUri,
            ResourceModel model,
            Expression resource,
            MemberAccess <Func <object, string> > uriGenerator,
            MemberAccess <Func <object, string> > typeGenerator,
            IMetaModelRepository models,
            Variable <HydraJsonFormatterResolver> jsonFormatterResolver,
            NodeProperty[] existingNodeProperties   = null,
            Stack <ResourceModel> recursionDefender = null)
        {
            recursionDefender = recursionDefender ?? new Stack <ResourceModel>();
            var resourceType = model.ResourceType;

            if (recursionDefender.Contains(model))
            {
                throw new InvalidOperationException(
                          $"Detected recursion, already processing {resourceType?.Name}: {string.Join("->", recursionDefender.Select(m => m.ResourceType?.Name).Where(n => n != null))}");
            }

            recursionDefender.Push(model);

            var resourceRegistrationHydraType = HydraTextExtensions.GetHydraTypeName(model);
            var resourceUri = uriGenerator.Invoke(resource);

            List <NodeProperty> nodeProperties =
                new List <NodeProperty>(existingNodeProperties ?? Enumerable.Empty <NodeProperty>());

            nodeProperties.AddRange(GetNodeProperties(
                                        jsonWriter,
                                        baseUri,
                                        model,
                                        resource,
                                        uriGenerator,
                                        typeGenerator,
                                        models,
                                        recursionDefender,
                                        jsonFormatterResolver,
                                        resourceType,
                                        resourceUri,
                                        resourceRegistrationHydraType));


            var  collectionItemTypes = HydraTextExtensions.CollectionItemTypes(resourceType).ToList();
            Type collectionItemType  = null;
            var  isHydraCollection   = collectionItemTypes.Count == 1 &&
                                       models.TryGetResourceModel(collectionItemType = collectionItemTypes.First(), out _);

            IEnumerable <AnyExpression> render()
            {
                if (isHydraCollection)
                {
                    var collectionType = HydraTypes.Collection.MakeGenericType(collectionItemType);
                    var collectionCtor =
                        collectionType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(collectionItemType) });
                    var collection = Expression.Variable(collectionType);

                    yield return(collection);

                    var instantiateCollection = Expression.Assign(collection, Expression.New(collectionCtor, resource));
                    yield return(instantiateCollection);

                    resource = collection;

                    // if we have a generic list of sort, we hydra:Collection instead
                    if (resourceType.IsGenericType) // IEnum<T>, List<T> etc
                    {
                        resourceRegistrationHydraType = "hydra:Collection";
                    }

                    resourceType = collectionType;

                    // Remove existing id and type if already defined
                    nodeProperties.RemoveAll(p => p.Name == "@id" || p.Name == "@type");
                    nodeProperties.AddRange(GetNodeProperties(jsonWriter, baseUri, model, resource, uriGenerator, typeGenerator,
                                                              models,
                                                              recursionDefender,
                                                              jsonFormatterResolver, resourceType, resourceUri, resourceRegistrationHydraType));
                }

                if (nodeProperties.Any())
                {
                    yield return(WriteNodeProperties(jsonWriter, nodeProperties));
                }
            }

            recursionDefender.Pop();
            return(new CodeBlock(render()));
        }
Exemplo n.º 2
0
        static IEnumerable <NodeProperty> GetNodeProperties(
            Variable <JsonWriter> jsonWriter,
            TypedExpression <string> baseUri,
            ResourceModel model,
            Expression resource,
            MemberAccess <Func <object, string> > uriGenerator,
            MemberAccess <Func <object, string> > typeGenerator,
            IMetaModelRepository models,
            Stack <ResourceModel> recursionDefender,
            Variable <HydraJsonFormatterResolver> jsonFormatterResolver,
            Type resourceType,
            TypedExpression <string> resourceUri,
            string resourceRegistrationHydraType)
        {
            var publicProperties = resourceType
                                   .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                   .Where(HydraTextExtensions.IsNotIgnored)
                                   .ToList();

            var propNames     = publicProperties.Select(HydraTextExtensions.GetJsonPropertyName);
            var overridesId   = propNames.Any(name => name == "@id");
            var overridesType = propNames.Any(name => name == "@type");

            if (overridesId == false && model.Uris.Any())
            {
                yield return(WriteId(jsonWriter, resourceUri));
            }

            if (overridesType == false)
            {
                var typePropertyFactory = model.Hydra().TypeFunc;
                if (typePropertyFactory == null)
                {
                    yield return(WriteType(jsonWriter, resourceRegistrationHydraType));
                }
                else
                {
                    yield return(WriteType(jsonWriter, StringMethods.Concat(baseUri, typeGenerator.Invoke(resource))));
                }
            }


            foreach (var pi in publicProperties)
            {
                if (pi.GetIndexParameters().Any())
                {
                    continue;
                }

                if (pi.PropertyType == typeof(string) ||
                    (pi.PropertyType.IsValueType && Nullable.GetUnderlyingType(pi.PropertyType) == null))
                {
                    var nodePropertyValue = WriteNodePropertyValue(
                        jsonWriter,
                        pi,
                        jsonFormatterResolver,
                        resource);

                    yield return(nodePropertyValue);

                    continue;
                }

                yield return(WriteNodeProperty(
                                 jsonWriter, baseUri, resource, uriGenerator, typeGenerator, models, recursionDefender, pi,
                                 jsonFormatterResolver));
            }

            foreach (var link in model.Links)
            {
                yield return(WriteNodeLink(jsonWriter, link.Relationship, link.Uri, resourceUri, link));
            }
        }