feat(Reflection): extract reflection capabilities into a separate module
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
import {FIELD, Type, isBlank} from 'facade/lang';
|
||||
import {FIELD, Type, isBlank, isPresent} from 'facade/lang';
|
||||
import {List, MapWrapper, ListWrapper} from 'facade/collection';
|
||||
import {reflector} from './reflector';
|
||||
import {reflector} from 'reflection/reflection';
|
||||
import {Key} from './key';
|
||||
import {Inject, InjectLazy, InjectPromise, DependencyAnnotation} from './annotations';
|
||||
import {NoAnnotationError} from './exceptions';
|
||||
|
||||
export class Dependency {
|
||||
key:Key;
|
||||
@ -43,8 +45,8 @@ export class BindingBuilder {
|
||||
toClass(type:Type):Binding {
|
||||
return new Binding(
|
||||
Key.get(this.token),
|
||||
reflector.factoryFor(type),
|
||||
reflector.dependencies(type),
|
||||
reflector.factory(type),
|
||||
_dependenciesFor(type),
|
||||
false
|
||||
);
|
||||
}
|
||||
@ -78,7 +80,49 @@ export class BindingBuilder {
|
||||
|
||||
_constructDependencies(factoryFunction:Function, dependencies:List) {
|
||||
return isBlank(dependencies) ?
|
||||
reflector.dependencies(factoryFunction) :
|
||||
_dependenciesFor(factoryFunction) :
|
||||
ListWrapper.map(dependencies, (t) => new Dependency(Key.get(t), false, false, []));
|
||||
}
|
||||
}
|
||||
|
||||
function _dependenciesFor(typeOrFunc):List {
|
||||
var params = reflector.parameters(typeOrFunc);
|
||||
if (isBlank(params)) return [];
|
||||
if (ListWrapper.any(params, (p) => isBlank(p))) throw new NoAnnotationError(typeOrFunc);
|
||||
return ListWrapper.map(params, (p) => _extractToken(typeOrFunc, p));
|
||||
}
|
||||
|
||||
function _extractToken(typeOrFunc, annotations) {
|
||||
var type;
|
||||
var depProps = [];
|
||||
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var paramAnnotation = annotations[i];
|
||||
|
||||
if (paramAnnotation instanceof Type) {
|
||||
type = paramAnnotation;
|
||||
|
||||
} else if (paramAnnotation instanceof Inject) {
|
||||
return _createDependency(paramAnnotation.token, false, false, []);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectPromise) {
|
||||
return _createDependency(paramAnnotation.token, true, false, []);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectLazy) {
|
||||
return _createDependency(paramAnnotation.token, false, true, []);
|
||||
|
||||
} else if (paramAnnotation instanceof DependencyAnnotation) {
|
||||
ListWrapper.push(depProps, paramAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPresent(type)) {
|
||||
return _createDependency(type, false, false, depProps);
|
||||
} else {
|
||||
throw new NoAnnotationError(typeOrFunc);
|
||||
}
|
||||
}
|
||||
|
||||
function _createDependency(token, asPromise, lazy, depProps):Dependency {
|
||||
return new Dependency(Key.get(token), asPromise, lazy, depProps);
|
||||
}
|
||||
|
@ -2,10 +2,9 @@ import {Map, List, MapWrapper, ListWrapper} from 'facade/collection';
|
||||
import {Binding, BindingBuilder, bind} from './binding';
|
||||
import {ProviderError, NoProviderError, InvalidBindingError,
|
||||
AsyncBindingError, CyclicDependencyError, InstantiationError} from './exceptions';
|
||||
import {Type, isPresent, isBlank} from 'facade/lang';
|
||||
import {FunctionWrapper, Type, isPresent, isBlank} from 'facade/lang';
|
||||
import {Promise, PromiseWrapper} from 'facade/async';
|
||||
import {Key} from './key';
|
||||
import {reflector} from './reflector';
|
||||
|
||||
var _constructing = new Object();
|
||||
|
||||
@ -159,7 +158,7 @@ class _SyncInjectorStrategy {
|
||||
|
||||
_createInstance(key:Key, binding:Binding, deps:List) {
|
||||
try {
|
||||
var instance = reflector.invoke(binding.factory, deps);
|
||||
var instance = FunctionWrapper.apply(binding.factory, deps);
|
||||
this.injector._setInstance(key, instance);
|
||||
return instance;
|
||||
} catch (e) {
|
||||
@ -221,7 +220,7 @@ class _AsyncInjectorStrategy {
|
||||
try {
|
||||
var instance = this.injector._getInstance(key);
|
||||
if (!_isWaiting(instance)) return instance;
|
||||
return reflector.invoke(binding.factory, deps);
|
||||
return FunctionWrapper.apply(binding.factory, deps);
|
||||
} catch (e) {
|
||||
this.injector._clear(key);
|
||||
throw new InstantiationError(e, key);
|
||||
|
@ -1,94 +0,0 @@
|
||||
library facade.di.reflector;
|
||||
|
||||
import 'dart:mirrors';
|
||||
import 'annotations.dart' show Inject, InjectPromise, InjectLazy, DependencyAnnotation;
|
||||
import 'key.dart' show Key;
|
||||
import 'binding.dart' show Dependency;
|
||||
import 'exceptions.dart' show NoAnnotationError;
|
||||
|
||||
class Reflector {
|
||||
Function factoryFor(Type type) {
|
||||
ClassMirror classMirror = reflectType(type);
|
||||
MethodMirror ctor = classMirror.declarations[classMirror.simpleName];
|
||||
Function create = classMirror.newInstance;
|
||||
Symbol name = ctor.constructorName;
|
||||
int length = ctor.parameters.length;
|
||||
|
||||
switch (length) {
|
||||
case 0: return () =>
|
||||
create(name, []).reflectee;
|
||||
case 1: return (a1) =>
|
||||
create(name, [a1]).reflectee;
|
||||
case 2: return (a1, a2) =>
|
||||
create(name, [a1, a2]).reflectee;
|
||||
case 3: return (a1, a2, a3) =>
|
||||
create(name, [a1, a2, a3]).reflectee;
|
||||
case 4: return (a1, a2, a3, a4) =>
|
||||
create(name, [a1, a2, a3, a4]).reflectee;
|
||||
case 5: return (a1, a2, a3, a4, a5) =>
|
||||
create(name, [a1, a2, a3, a4, a5]).reflectee;
|
||||
case 6: return (a1, a2, a3, a4, a5, a6) =>
|
||||
create(name, [a1, a2, a3, a4, a5, a6]).reflectee;
|
||||
case 7: return (a1, a2, a3, a4, a5, a6, a7) =>
|
||||
create(name, [a1, a2, a3, a4, a5, a6, a7]).reflectee;
|
||||
case 8: return (a1, a2, a3, a4, a5, a6, a7, a8) =>
|
||||
create(name, [a1, a2, a3, a4, a5, a6, a7, a8]).reflectee;
|
||||
case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) =>
|
||||
create(name, [a1, a2, a3, a4, a5, a6, a7, a8, a9]).reflectee;
|
||||
case 10: return (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) =>
|
||||
create(name, [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]).reflectee;
|
||||
};
|
||||
|
||||
throw "Factory cannot take more than 10 arguments";
|
||||
}
|
||||
|
||||
invoke(Function factory, List args) {
|
||||
return Function.apply(factory, args);
|
||||
}
|
||||
|
||||
List<Dependency> dependencies(typeOrFunc) {
|
||||
final parameters = typeOrFunc is Type ?
|
||||
_constructorParameters(typeOrFunc) :
|
||||
_functionParameters(typeOrFunc);
|
||||
|
||||
return new List.generate(parameters.length, (int pos) {
|
||||
ParameterMirror p = parameters[pos];
|
||||
|
||||
final metadata = p.metadata.map((m) => m.reflectee);
|
||||
|
||||
var inject = metadata.firstWhere((m) => m is Inject, orElse: () => null);
|
||||
var injectPromise = metadata.firstWhere((m) => m is InjectPromise, orElse: () => null);
|
||||
var injectLazy = metadata.firstWhere((m) => m is InjectLazy, orElse: () => null);
|
||||
|
||||
if (inject != null) {
|
||||
return new Dependency(Key.get(inject.token), false, false, []);
|
||||
|
||||
} else if (injectPromise != null) {
|
||||
return new Dependency(Key.get(injectPromise.token), true, false, []);
|
||||
|
||||
} else if (injectLazy != null) {
|
||||
return new Dependency(Key.get(injectLazy.token), false, true, []);
|
||||
|
||||
} else if (p.type.qualifiedName != #dynamic) {
|
||||
var depProps = metadata.where((m) => m is DependencyAnnotation).toList();
|
||||
return new Dependency(Key.get(p.type.reflectedType), false, false, depProps);
|
||||
|
||||
} else {
|
||||
throw new NoAnnotationError(typeOrFunc);
|
||||
}
|
||||
}, growable:false);
|
||||
}
|
||||
|
||||
List<ParameterMirror> _functionParameters(Function func) {
|
||||
var closureMirror = reflect(func);
|
||||
return closureMirror.function.parameters;
|
||||
}
|
||||
|
||||
List<ParameterMirror> _constructorParameters(Type type) {
|
||||
ClassMirror classMirror = reflectType(type);
|
||||
MethodMirror ctor = classMirror.declarations[classMirror.simpleName];
|
||||
return ctor.parameters;
|
||||
}
|
||||
}
|
||||
|
||||
final Reflector reflector = new Reflector();
|
@ -1,84 +0,0 @@
|
||||
import {Type, isPresent} from 'facade/lang';
|
||||
import {List} from 'facade/collection';
|
||||
import {Inject, InjectPromise, InjectLazy, DependencyAnnotation} from './annotations';
|
||||
import {Key} from './key';
|
||||
import {Dependency} from './binding';
|
||||
import {NoAnnotationError} from './exceptions';
|
||||
|
||||
class Reflector {
|
||||
factoryFor(type:Type):Function {
|
||||
var length = type.parameters ? type.parameters.length : 0;
|
||||
switch (length) {
|
||||
case 0: return () =>
|
||||
new type();
|
||||
case 1: return (a1) =>
|
||||
new type(a1);
|
||||
case 2: return (a1, a2) =>
|
||||
new type(a1, a2);
|
||||
case 3: return (a1, a2, a3) =>
|
||||
new type(a1, a2, a3);
|
||||
case 4: return (a1, a2, a3, a4) =>
|
||||
new type(a1, a2, a3, a4);
|
||||
case 5: return (a1, a2, a3, a4, a5) =>
|
||||
new type(a1, a2, a3, a4, a5);
|
||||
case 6: return (a1, a2, a3, a4, a5, a6) =>
|
||||
new type(a1, a2, a3, a4, a5, a6);
|
||||
case 7: return (a1, a2, a3, a4, a5, a6, a7) =>
|
||||
new type(a1, a2, a3, a4, a5, a6, a7);
|
||||
case 8: return (a1, a2, a3, a4, a5, a6, a7, a8) =>
|
||||
new type(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) =>
|
||||
new type(a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
case 10: return (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) =>
|
||||
new type(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
|
||||
};
|
||||
|
||||
throw "Factory cannot take more than 10 arguments";
|
||||
}
|
||||
|
||||
invoke(factory:Function, args:List) {
|
||||
return factory(...args);
|
||||
}
|
||||
|
||||
dependencies(typeOrFunc):List {
|
||||
var p = typeOrFunc.parameters;
|
||||
if (p == undefined && typeOrFunc.length == 0) return [];
|
||||
if (p == undefined) throw new NoAnnotationError(typeOrFunc);
|
||||
return typeOrFunc.parameters.map((p) => this._extractToken(typeOrFunc, p));
|
||||
}
|
||||
|
||||
_extractToken(typeOrFunc, annotations) {
|
||||
var type;
|
||||
var depProps = [];
|
||||
|
||||
for (var paramAnnotation of annotations) {
|
||||
if (paramAnnotation instanceof Type) {
|
||||
type = paramAnnotation;
|
||||
|
||||
} else if (paramAnnotation instanceof Inject) {
|
||||
return this._createDependency(paramAnnotation.token, false, false, []);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectPromise) {
|
||||
return this._createDependency(paramAnnotation.token, true, false, []);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectLazy) {
|
||||
return this._createDependency(paramAnnotation.token, false, true, []);
|
||||
|
||||
} else if (paramAnnotation instanceof DependencyAnnotation) {
|
||||
depProps.push(paramAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPresent(type)) {
|
||||
return this._createDependency(type, false, false, depProps);
|
||||
} else {
|
||||
throw new NoAnnotationError(typeOrFunc);
|
||||
}
|
||||
}
|
||||
|
||||
_createDependency(token, asPromise, lazy, depProps):Dependency {
|
||||
return new Dependency(Key.get(token), asPromise, lazy, depProps);
|
||||
}
|
||||
}
|
||||
|
||||
export var reflector:Reflector = new Reflector();
|
Reference in New Issue
Block a user