Skip to content

Commit

Permalink
Merge pull request #25 from graphql-dotnet/fix-reflection-and-depende…
Browse files Browse the repository at this point in the history
…ncy-injection

Fix reflection and dependency injection
  • Loading branch information
tlil authored Feb 16, 2017
2 parents 573b877 + 3080549 commit 54db9b7
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 48 deletions.
38 changes: 33 additions & 5 deletions src/GraphQL.Conventions/Adapters/Engine/GraphQLEngine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -50,16 +51,19 @@ public INodeVisitor Validate(ValidationContext context)

private class WrappedDependencyInjector : IDependencyInjector
{
private readonly GraphQLEngine _engine;

private readonly Func<System.Type, object> _typeResolutionDelegate;

public WrappedDependencyInjector(Func<System.Type, object> typeResolutionDelegate)
public WrappedDependencyInjector(GraphQLEngine engine, Func<System.Type, object> typeResolutionDelegate)
{
_engine = engine;
_typeResolutionDelegate = typeResolutionDelegate;
}

public object Resolve(System.Reflection.TypeInfo typeInfo)
{
return _typeResolutionDelegate(typeInfo.AsType());
return _typeResolutionDelegate(typeInfo.AsType()) ?? _engine.CreateInstance(typeInfo.AsType());
}
}

Expand All @@ -68,13 +72,13 @@ public GraphQLEngine(Func<System.Type, object> typeResolutionDelegate = null)
_constructor = new SchemaConstructor<ISchema, IGraphType>(_graphTypeAdapter, _typeResolver);
if (typeResolutionDelegate != null)
{
_typeResolver.DependencyInjector = new WrappedDependencyInjector(typeResolutionDelegate);
_constructor.TypeResolutionDelegate = typeResolutionDelegate;
_typeResolver.DependencyInjector = new WrappedDependencyInjector(this, typeResolutionDelegate);
_constructor.TypeResolutionDelegate = type => typeResolutionDelegate(type) ?? CreateInstance(type);
}
else
{
_constructor.TypeResolutionDelegate = type =>
_typeResolver?.DependencyInjector?.Resolve(type.GetTypeInfo()) ?? Activator.CreateInstance(type);
_typeResolver?.DependencyInjector?.Resolve(type.GetTypeInfo()) ?? CreateInstance(type);
}
}

Expand Down Expand Up @@ -228,5 +232,29 @@ internal IValidationResult Validate(string queryString)
var document = _documentBuilder.Build(queryString);
return _documentValidator.Validate(queryString, _schema, document);
}

private object CreateInstance(System.Type type)
{
var typeInfo = type.GetTypeInfo();
if (!typeInfo.IsAbstract && !typeInfo.ContainsGenericParameters)
{
var ctors = typeInfo.GetConstructors().ToList();
if (ctors.All(ctor => ctor.GetParameters().Any()))
{
var ctor = ctors.FirstOrDefault();
if (ctor == null)
{
return null;
}
var parameters = ctor.GetParameters();
var parameterValues = parameters
.Select(parameter => _constructor.TypeResolutionDelegate(parameter.ParameterType))
.ToArray();
return ctor.Invoke(parameterValues);
}
}

return Activator.CreateInstance(type);
}
}
}
33 changes: 12 additions & 21 deletions src/GraphQL.Conventions/Adapters/GraphTypeAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@ namespace GraphQL.Conventions.Adapters
{
public class GraphTypeAdapter : IGraphTypeAdapter<ISchema, IGraphType>
{
public static ILogger Logger { get; set; }

private readonly CachedRegistry<Type, IGraphType> _typeDescriptors = new CachedRegistry<Type, IGraphType>();

private readonly Dictionary<string, Type> _registeredScalarTypes = new Dictionary<string, Type>();

public ISchema DeriveSchema(GraphSchemaInfo schemaInfo)
{
Logger?.Trace($"Deriving Schema(Query={schemaInfo?.Query?.Name}, Mutation={schemaInfo?.Mutation?.Name})");
var types = schemaInfo
.Types
.Where(t => !t.IsIgnored && !t.Interfaces.Any(iface => iface.IsIgnored))
Expand All @@ -27,11 +24,14 @@ public ISchema DeriveSchema(GraphSchemaInfo schemaInfo)
DeriveType(type);
}
var interfaces = types
.Where(t => t.IsInterfaceType && t.PossibleTypes.Any());
.Where(t => t.IsInterfaceType && !t.IsInputType && t.PossibleTypes.Any())
.GroupBy(t => t.Name)
.Select(g => g.First());
var possibleTypes = interfaces
.Where(t => !t.IsIgnored)
.SelectMany(t => t.PossibleTypes)
.Distinct();
.GroupBy(t => t.Name)
.Select(g => g.First());
var schema = new Schema(DeriveTypeFromTypeInfo)
{
Query = DeriveOperationType(schemaInfo.Query),
Expand All @@ -47,7 +47,6 @@ public ISchema DeriveSchema(GraphSchemaInfo schemaInfo)

public IGraphType DeriveType(GraphTypeInfo typeInfo)
{
Logger?.Trace($"Deriving Type={typeInfo?.Name}");
var primitiveType = GetPrimitiveType(typeInfo);
var graphType = primitiveType != null
? WrapNonNullableType(typeInfo, Activator.CreateInstance(primitiveType) as GraphType)
Expand All @@ -57,7 +56,6 @@ public IGraphType DeriveType(GraphTypeInfo typeInfo)

public void RegisterScalarType<TType>(string name)
{
Logger?.Trace($"Registering Scalar(Name={name}, Type={typeof(TType).Name}");
_registeredScalarTypes.Add(name, typeof(TType));
}

Expand All @@ -66,10 +64,8 @@ private IGraphType DeriveTypeFromTypeInfo(Type type)
var graphType = _typeDescriptors.GetEntity(type);
if (graphType != null)
{
Logger?.Trace($"Deriving representation for Type={type?.Name}");
return graphType;
}
Logger?.Trace($"Instantiating representation for Type={type?.Name}");
return (IGraphType)Activator.CreateInstance(type);
}

Expand All @@ -80,7 +76,6 @@ private IObjectGraphType DeriveOperationType(GraphTypeInfo typeInfo) =>

private FieldType DeriveField(GraphFieldInfo fieldInfo)
{
Logger?.Trace($"Deriving Field={fieldInfo?.Name}");
return new FieldType
{
Name = fieldInfo.Name,
Expand All @@ -95,7 +90,6 @@ private FieldType DeriveField(GraphFieldInfo fieldInfo)

private QueryArgument DeriveArgument(GraphArgumentInfo argumentInfo)
{
Logger?.Trace($"Deriving Field={argumentInfo?.Name}");
return new QueryArgument(GetType(argumentInfo.Type))
{
Name = argumentInfo.Name,
Expand Down Expand Up @@ -132,13 +126,11 @@ private Type GetPrimitiveType(GraphTypeInfo typeInfo)
return typeof(Types.UriGraphType);
default:
Type type;
Logger?.Trace($"Deriving PrimitiveType={typeInfo?.Name}");
if (!string.IsNullOrWhiteSpace(typeInfo.Name) &&
_registeredScalarTypes.TryGetValue(typeInfo.Name, out type))
{
return type;
}
Logger?.Warning($"Failed deriving PrimitiveType={typeInfo?.Name}");
return null;
}
}
Expand All @@ -147,32 +139,26 @@ private IGraphType GetComplexType(GraphTypeInfo typeInfo)
{
if (typeInfo.IsInterfaceType)
{
Logger?.Trace($"Constructing InterfaceType={typeInfo?.Name}");
return ConstructInterfaceType(typeInfo);
}
else if (typeInfo.IsEnumerationType)
{
Logger?.Trace($"Constructing EnumerationType={typeInfo?.Name}");
return ConstructEnumerationType(typeInfo);
}
else if (typeInfo.IsUnionType)
{
Logger?.Trace($"Constructing UnionType={typeInfo?.Name}");
return ConstructUnionType(typeInfo);
}
else if (typeInfo.IsListType)
{
Logger?.Trace($"Constructing ListType={typeInfo?.Name}");
return ConstructListType(typeInfo);
}
else if (typeInfo.IsInputType)
{
Logger?.Trace($"Constructing InputType={typeInfo?.Name}");
return ConstructInputType(typeInfo);
}
else if (typeInfo.IsOutputType)
{
Logger?.Trace($"Constructing OutputType={typeInfo?.Name}");
return ConstructOutputType(typeInfo);
}
else
Expand All @@ -191,7 +177,6 @@ private IGraphType CacheType(GraphTypeInfo typeInfo, IGraphType graphType)

private TType CreateTypeInstance<TType>(Type type)
{
Logger?.Trace($"Creating TypeInstance={type?.Name}");
var obj = Activator.CreateInstance(type);
return obj is TType ? (TType)obj : default(TType);
}
Expand Down Expand Up @@ -233,8 +218,14 @@ private IGraphType ConstructInterfaceType(GraphTypeInfo typeInfo)
{
return WrapNonNullableType(typeInfo, graphType);
}
foreach (var possibleType in typeInfo.PossibleTypes.Select(t => DeriveType(t) as IObjectGraphType))
foreach (var possibleType in typeInfo
.PossibleTypes
.Select(t => DeriveType(t) as IObjectGraphType))
{
if (possibleType == null)
{
continue;
}
graphType.AddPossibleType(possibleType);
}
DeriveFields(typeInfo, graphType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

namespace GraphQL.Conventions.Attributes.Collectors
{
public class AttributeCollector
{
public static Type ApplicationType { get; set; }
}

public class AttributeCollector<TAttribute>
where TAttribute : IAttribute
{
Expand Down Expand Up @@ -48,6 +53,10 @@ public int CompareTo(WrappedAttribute other)
public AttributeCollector()
{
DiscoverDefaultAttributes();
if (AttributeCollector.ApplicationType != null)
{
DiscoverDefaultAttributes(AttributeCollector.ApplicationType);
}
}

public List<TAttribute> CollectAttributes(ICustomAttributeProvider obj)
Expand All @@ -60,6 +69,10 @@ public List<TAttribute> CollectAttributes(ICustomAttributeProvider obj)

protected void AddDefaultAttributes(params TAttribute[] defaultAttributes)
{
if (_defaultAttributes == null)
{
_defaultAttributes = new List<TAttribute>();
}
_defaultAttributes.AddRange(defaultAttributes);
}

Expand All @@ -81,11 +94,12 @@ private void DiscoverDefaultAttributes(Type assemblyType = null)
}

var assembly = assemblyType.GetTypeInfo().Assembly;
_defaultAttributes = assembly
var defaultAttributes = assembly
.GetTypes()
.Where(type => IsDefaultAttribute(type) && IsTAttribute(type))
.Select(type => (TAttribute)Activator.CreateInstance(type))
.ToList();
.ToArray();
AddDefaultAttributes(defaultAttributes);
}

private void DiscoverDefaultAttributes()
Expand Down
10 changes: 5 additions & 5 deletions src/GraphQL.Conventions/Builders/SchemaConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public TSchemaType Build<TSchema>() =>
Build(typeof(TSchema).GetTypeInfo());

public TSchemaType Build(params Type[] schemaTypes) =>
Build(schemaTypes?.Select(type => type.GetTypeInfo()).ToArray());
Build(schemaTypes?.Select(type => type?.GetTypeInfo()).ToArray());

public TSchemaType Build(params TypeInfo[] schemaTypes)
{
Expand All @@ -56,7 +56,7 @@ public TSchemaType Build(params TypeInfo[] schemaTypes)
{
if (schemaInfo.Query != null)
{
schemaInfo.Query.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Query.Fields));
schemaInfo.Query.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Query?.Fields));
schemaInfo.Query.Fields = schemaInfo.Query.Fields.OrderBy(f => f.Name).ToList();
}
else
Expand All @@ -66,7 +66,7 @@ public TSchemaType Build(params TypeInfo[] schemaTypes)

if (schemaInfo.Mutation != null)
{
schemaInfo.Mutation.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Mutation.Fields));
schemaInfo.Mutation.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Mutation?.Fields));
schemaInfo.Mutation.Fields = schemaInfo.Mutation.Fields.OrderBy(f => f.Name).ToList();
}
else
Expand All @@ -76,7 +76,7 @@ public TSchemaType Build(params TypeInfo[] schemaTypes)

if (schemaInfo.Subscription != null)
{
schemaInfo.Subscription.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Subscription.Fields));
schemaInfo.Subscription.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Subscription?.Fields));
schemaInfo.Subscription.Fields = schemaInfo.Subscription.Fields.OrderBy(f => f.Name).ToList();
}
else
Expand Down Expand Up @@ -117,7 +117,7 @@ private IEnumerable<GraphFieldInfo> RemoveDuplicateViewers(IEnumerable<GraphFiel
typeof(ImplementViewerAttribute.SubscriptionViewerReferrer),
};

foreach (var field in fields)
foreach (var field in fields ?? new List<GraphFieldInfo>())
{
if (field.Name == "viewer" &&
registeredViewerClasses.Contains(field.DeclaringType.TypeRepresentation.AsType()))
Expand Down
6 changes: 3 additions & 3 deletions src/GraphQL.Conventions/CommonAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
[assembly: AssemblyProduct("GraphQL.Conventions")]
[assembly: AssemblyCopyright("Copyright 2016-2017 Tommy Lillehagen. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("1.1.1.0")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1.0")]
[assembly: AssemblyVersion("1.1.2.0")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2.0")]
[assembly: CLSCompliant(false)]

[assembly: InternalsVisibleTo("GraphQL.Conventions.Tests")]
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ private void ResolveArgument(GraphArgumentInfo argument, IResolutionContext reso
{
object obj;
var argumentType = (TypeInfo)argument.Type.AttributeProvider;
if (argumentType.AsType() == typeof(IResolutionContext))
if (argumentType.AsType() == typeof(IResolutionContext) ||
argumentType.ImplementedInterfaces.Any(iface => iface == typeof(IResolutionContext)))
{
obj = resolutionContext;
}
else if (argumentType.AsType() == typeof(IUserContext))
else if (argumentType.AsType() == typeof(IUserContext) ||
argumentType.ImplementedInterfaces.Any(iface => iface == typeof(IUserContext)))
{
obj = resolutionContext.UserContext;
}
Expand Down
6 changes: 6 additions & 0 deletions src/GraphQL.Conventions/Handlers/MetaDataAttributeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ class MetaDataAttributeHandler<TAttribute>
private readonly AttributeCollector<IExecutionFilterAttribute> _executionFilterCollector =
new AttributeCollector<IExecutionFilterAttribute>();

public bool HasAttribute<T>(ICustomAttributeProvider obj)
{
var attributes = _collector.CollectAttributes(obj);
return attributes.Any(attr => attr.GetType() == typeof(T));
}

public void DeriveMetaData(GraphEntityInfo entity, ICustomAttributeProvider obj)
{
var attributes = _collector.CollectAttributes(obj);
Expand Down
2 changes: 1 addition & 1 deletion src/GraphQL.Conventions/Types/Descriptors/GraphTypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public GraphTypeInfo(ITypeResolver typeResolver, TypeInfo type)

public List<GraphTypeInfo> PossibleTypes => _possibleTypes;

public List<GraphTypeInfo> UnionTypes => PossibleTypes;
public List<GraphTypeInfo> UnionTypes => IsUnionType ? PossibleTypes : new List<GraphTypeInfo>();

public List<GraphFieldInfo> Fields { get; internal set; } = new List<GraphFieldInfo>();

Expand Down
Loading

0 comments on commit 54db9b7

Please sign in to comment.