refactor(core): separate reflective injector from Injector interface

BREAKING CHANGE:
- Injector was renamed into `ReflectiveInjector`,
  as `Injector` is only an abstract class with one method on it
- `Injector.getOptional()` was changed into `Injector.get(token, notFoundValue)`
  to make implementing injectors simpler
- `ViewContainerRef.createComponent` now takes an `Injector`
  instead of `ResolvedProviders`. If a reflective injector
  should be used, create one before calling this method.
  (e.g. via `ReflectiveInjector.resolveAndCreate(…)`.
This commit is contained in:
Tobias Bosch
2016-04-14 12:35:24 -07:00
parent efbd446d18
commit 0a7d10ba55
46 changed files with 1790 additions and 1719 deletions
@@ -10,7 +10,7 @@ import {
} from 'angular2/testing_internal';
import {SpyIterableDifferFactory} from '../../spies';
import {IterableDiffers} from 'angular2/src/core/change_detection/differs/iterable_differs';
import {Injector, provide} from 'angular2/core';
import {Injector, provide, ReflectiveInjector} from 'angular2/core';
export function main() {
describe('IterableDiffers', function() {
@@ -51,7 +51,7 @@ export function main() {
describe(".extend()", () => {
it('should throw if calling extend when creating root injector', () => {
var injector = Injector.resolveAndCreate([IterableDiffers.extend([])]);
var injector = ReflectiveInjector.resolveAndCreate([IterableDiffers.extend([])]);
expect(() => injector.get(IterableDiffers))
.toThrowErrorWith("Cannot extend IterableDiffers without a parent injector");
@@ -59,7 +59,8 @@ export function main() {
it('should extend di-inherited diffesr', () => {
var parent = new IterableDiffers([factory1]);
var injector = Injector.resolveAndCreate([provide(IterableDiffers, {useValue: parent})]);
var injector =
ReflectiveInjector.resolveAndCreate([provide(IterableDiffers, {useValue: parent})]);
var childInjector = injector.resolveAndCreateChild([IterableDiffers.extend([factory2])]);
expect(injector.get(IterableDiffers).factories).toEqual([factory1]);
@@ -2,10 +2,10 @@ import {isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {describe, ddescribe, it, iit, expect, beforeEach} from 'angular2/testing_internal';
import {
Injector,
provide,
ResolvedProvider,
Key,
ReflectiveKey,
ReflectiveInjector,
Injector,
forwardRef,
Injectable,
InjectMetadata,
@@ -15,15 +15,14 @@ import {
Inject,
Provider
} from 'angular2/core';
import {Injector_} from 'angular2/src/core/di/injector';
import {DependencyMetadata} from 'angular2/src/core/di/metadata';
import {ResolvedProvider_} from 'angular2/src/core/di/provider';
import {
InjectorInlineStrategy,
InjectorDynamicStrategy,
ProtoInjector
} from 'angular2/src/core/di/injector';
ReflectiveInjector_,
ReflectiveInjectorInlineStrategy,
ReflectiveInjectorDynamicStrategy,
ReflectiveProtoInjector
} from 'angular2/src/core/di/reflective_injector';
import {DependencyMetadata} from 'angular2/src/core/di/metadata';
import {ResolvedReflectiveProvider_} from 'angular2/src/core/di/reflective_provider';
class CustomDependencyMetadata extends DependencyMetadata {}
@@ -102,18 +101,19 @@ export function main() {
provide('provider10', {useValue: 1})
];
[{strategy: 'inline', providers: [], strategyClass: InjectorInlineStrategy},
[{strategy: 'inline', providers: [], strategyClass: ReflectiveInjectorInlineStrategy},
{
strategy: 'dynamic',
providers: dynamicProviders,
strategyClass: InjectorDynamicStrategy
strategyClass: ReflectiveInjectorDynamicStrategy
}].forEach((context) => {
function createInjector(providers: any[], parent: Injector = null): Injector_ {
var resolvedProviders = Injector.resolve(providers.concat(context['providers']));
function createInjector(providers: any[],
parent: ReflectiveInjector = null): ReflectiveInjector_ {
var resolvedProviders = ReflectiveInjector.resolve(providers.concat(context['providers']));
if (isPresent(parent)) {
return <Injector_>parent.createChildFromResolved(resolvedProviders);
return <ReflectiveInjector_>parent.createChildFromResolved(resolvedProviders);
} else {
return <Injector_>Injector.fromResolvedProviders(resolvedProviders);
return <ReflectiveInjector_>ReflectiveInjector.fromResolvedProviders(resolvedProviders);
}
}
@@ -357,9 +357,10 @@ export function main() {
});
it('should show the full path when error happens in a constructor', () => {
var providers = Injector.resolve([Car, provide(Engine, {useClass: BrokenEngine})]);
var proto = new ProtoInjector([providers[0], providers[1]]);
var injector = new Injector_(proto);
var providers =
ReflectiveInjector.resolve([Car, provide(Engine, {useClass: BrokenEngine})]);
var proto = new ReflectiveProtoInjector([providers[0], providers[1]]);
var injector = new ReflectiveInjector_(proto);
try {
injector.get(Car);
@@ -373,14 +374,15 @@ export function main() {
});
it('should provide context when throwing an exception ', () => {
var engineProvider = Injector.resolve([provide(Engine, {useClass: BrokenEngine})])[0];
var protoParent = new ProtoInjector([engineProvider]);
var engineProvider =
ReflectiveInjector.resolve([provide(Engine, {useClass: BrokenEngine})])[0];
var protoParent = new ReflectiveProtoInjector([engineProvider]);
var carProvider = Injector.resolve([Car])[0];
var protoChild = new ProtoInjector([carProvider]);
var carProvider = ReflectiveInjector.resolve([Car])[0];
var protoChild = new ReflectiveProtoInjector([carProvider]);
var parent = new Injector_(protoParent, null, () => "parentContext");
var child = new Injector_(protoChild, parent, () => "childContext");
var parent = new ReflectiveInjector_(protoParent, null, () => "parentContext");
var child = new ReflectiveInjector_(protoChild, parent, () => "childContext");
try {
child.get(Car);
@@ -415,7 +417,7 @@ export function main() {
describe("child", () => {
it('should load instances from parent injector', () => {
var parent = Injector.resolveAndCreate([Engine]);
var parent = ReflectiveInjector.resolveAndCreate([Engine]);
var child = parent.resolveAndCreateChild([]);
var engineFromParent = parent.get(Engine);
@@ -426,7 +428,7 @@ export function main() {
it("should not use the child providers when resolving the dependencies of a parent provider",
() => {
var parent = Injector.resolveAndCreate([Car, Engine]);
var parent = ReflectiveInjector.resolveAndCreate([Car, Engine]);
var child = parent.resolveAndCreateChild([provide(Engine, {useClass: TurboEngine})]);
var carFromChild = child.get(Car);
@@ -434,7 +436,7 @@ export function main() {
});
it('should create new instance in a child injector', () => {
var parent = Injector.resolveAndCreate([Engine]);
var parent = ReflectiveInjector.resolveAndCreate([Engine]);
var child = parent.resolveAndCreateChild([provide(Engine, {useClass: TurboEngine})]);
var engineFromParent = parent.get(Engine);
@@ -445,7 +447,7 @@ export function main() {
});
it("should give access to parent", () => {
var parent = Injector.resolveAndCreate([]);
var parent = ReflectiveInjector.resolveAndCreate([]);
var child = parent.resolveAndCreateChild([]);
expect(child.parent).toBe(parent);
});
@@ -453,14 +455,14 @@ export function main() {
describe('resolveAndInstantiate', () => {
it('should instantiate an object in the context of the injector', () => {
var inj = Injector.resolveAndCreate([Engine]);
var inj = ReflectiveInjector.resolveAndCreate([Engine]);
var car = inj.resolveAndInstantiate(Car);
expect(car).toBeAnInstanceOf(Car);
expect(car.engine).toBe(inj.get(Engine));
});
it('should not store the instantiated object in the injector', () => {
var inj = Injector.resolveAndCreate([Engine]);
var inj = ReflectiveInjector.resolveAndCreate([Engine]);
inj.resolveAndInstantiate(Car);
expect(() => inj.get(Car)).toThrowError();
});
@@ -468,8 +470,8 @@ export function main() {
describe('instantiate', () => {
it('should instantiate an object in the context of the injector', () => {
var inj = Injector.resolveAndCreate([Engine]);
var car = inj.instantiateResolved(Injector.resolve([Car])[0]);
var inj = ReflectiveInjector.resolveAndCreate([Engine]);
var car = inj.instantiateResolved(ReflectiveInjector.resolve([Car])[0]);
expect(car).toBeAnInstanceOf(Car);
expect(car.engine).toBe(inj.get(Engine));
});
@@ -478,7 +480,7 @@ export function main() {
describe("depedency resolution", () => {
describe("@Self()", () => {
it("should return a dependency from self", () => {
var inj = Injector.resolveAndCreate([
var inj = ReflectiveInjector.resolveAndCreate([
Engine,
provide(Car, {useFactory: (e) => new Car(e), deps: [[Engine, new SelfMetadata()]]})
]);
@@ -487,7 +489,7 @@ export function main() {
});
it("should throw when not requested provider on self", () => {
var parent = Injector.resolveAndCreate([Engine]);
var parent = ReflectiveInjector.resolveAndCreate([Engine]);
var child = parent.resolveAndCreateChild([
provide(Car, {useFactory: (e) => new Car(e), deps: [[Engine, new SelfMetadata()]]})
]);
@@ -499,7 +501,7 @@ export function main() {
describe("default", () => {
it("should not skip self", () => {
var parent = Injector.resolveAndCreate([Engine]);
var parent = ReflectiveInjector.resolveAndCreate([Engine]);
var child = parent.resolveAndCreateChild([
provide(Engine, {useClass: TurboEngine}),
provide(Car, {useFactory: (e) => new Car(e), deps: [Engine]})
@@ -512,15 +514,15 @@ export function main() {
describe('resolve', () => {
it('should resolve and flatten', () => {
var providers = Injector.resolve([Engine, [BrokenEngine]]);
var providers = ReflectiveInjector.resolve([Engine, [BrokenEngine]]);
providers.forEach(function(b) {
if (isBlank(b)) return; // the result is a sparse array
expect(b instanceof ResolvedProvider_).toBe(true);
expect(b instanceof ResolvedReflectiveProvider_).toBe(true);
});
});
it("should support multi providers", () => {
var provider = Injector.resolve([
var provider = ReflectiveInjector.resolve([
new Provider(Engine, {useClass: BrokenEngine, multi: true}),
new Provider(Engine, {useClass: TurboEngine, multi: true})
])[0];
@@ -531,8 +533,8 @@ export function main() {
});
it("should support multi providers with only one provider", () => {
var provider =
Injector.resolve([new Provider(Engine, {useClass: BrokenEngine, multi: true})])[0];
var provider = ReflectiveInjector.resolve(
[new Provider(Engine, {useClass: BrokenEngine, multi: true})])[0];
expect(provider.key.token).toBe(Engine);
expect(provider.multiProvider).toEqual(true);
@@ -541,16 +543,18 @@ export function main() {
it("should throw when mixing multi providers with regular providers", () => {
expect(() => {
Injector.resolve([new Provider(Engine, {useClass: BrokenEngine, multi: true}), Engine]);
ReflectiveInjector.resolve(
[new Provider(Engine, {useClass: BrokenEngine, multi: true}), Engine]);
}).toThrowErrorWith("Cannot mix multi providers and regular providers");
expect(() => {
Injector.resolve([Engine, new Provider(Engine, {useClass: BrokenEngine, multi: true})]);
ReflectiveInjector.resolve(
[Engine, new Provider(Engine, {useClass: BrokenEngine, multi: true})]);
}).toThrowErrorWith("Cannot mix multi providers and regular providers");
});
it('should resolve forward references', () => {
var providers = Injector.resolve([
var providers = ReflectiveInjector.resolve([
forwardRef(() => Engine),
[provide(forwardRef(() => BrokenEngine), {useClass: forwardRef(() => Engine)})],
provide(forwardRef(() => String),
@@ -563,11 +567,12 @@ export function main() {
expect(engineProvider.resolvedFactories[0].factory() instanceof Engine).toBe(true);
expect(brokenEngineProvider.resolvedFactories[0].factory() instanceof Engine).toBe(true);
expect(stringProvider.resolvedFactories[0].dependencies[0].key).toEqual(Key.get(Engine));
expect(stringProvider.resolvedFactories[0].dependencies[0].key)
.toEqual(ReflectiveKey.get(Engine));
});
it('should support overriding factory dependencies with dependency annotations', () => {
var providers = Injector.resolve([
var providers = ReflectiveInjector.resolve([
provide("token",
{
useFactory: (e) => "result",
@@ -583,9 +588,9 @@ export function main() {
});
it('should allow declaring dependencies with flat arrays', () => {
var resolved = Injector.resolve(
var resolved = ReflectiveInjector.resolve(
[provide('token', {useFactory: e => e, deps: [new InjectMetadata("dep")]})]);
var nestedResolved = Injector.resolve(
var nestedResolved = ReflectiveInjector.resolve(
[provide('token', {useFactory: e => e, deps: [[new InjectMetadata("dep")]]})]);
expect(resolved[0].resolvedFactories[0].dependencies[0].key.token)
.toEqual(nestedResolved[0].resolvedFactories[0].dependencies[0].key.token);
@@ -594,8 +599,9 @@ export function main() {
describe("displayName", () => {
it("should work", () => {
expect((<Injector_>Injector.resolveAndCreate([Engine, BrokenEngine])).displayName)
.toEqual('Injector(providers: [ "Engine" , "BrokenEngine" ])');
expect((<ReflectiveInjector_>ReflectiveInjector.resolveAndCreate([Engine, BrokenEngine]))
.displayName)
.toEqual('ReflectiveInjector(providers: [ "Engine" , "BrokenEngine" ])');
});
});
});
@@ -1,5 +1,5 @@
import {describe, iit, it, expect, beforeEach} from 'angular2/testing_internal';
import {Key, KeyRegistry} from 'angular2/src/core/di/key';
import {ReflectiveKey, KeyRegistry} from 'angular2/src/core/di/reflective_key';
export function main() {
describe("key", function() {
@@ -54,7 +54,8 @@ import {
Host,
SkipSelf,
SkipSelfMetadata,
OnDestroy
OnDestroy,
ReflectiveInjector
} from 'angular2/core';
import {NgIf, NgFor} from 'angular2/common';
@@ -1409,7 +1410,7 @@ function declareTests(isJit: boolean) {
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
var c = e.context;
expect(DOM.nodeName(c.componentRenderElement).toUpperCase()).toEqual("DIV");
expect(c.injector.getOptional).toBeTruthy();
expect((<Injector>c.injector).get).toBeTruthy();
async.done();
return null;
});
@@ -1429,7 +1430,7 @@ function declareTests(isJit: boolean) {
var c = e.context;
expect(DOM.nodeName(c.renderNode).toUpperCase()).toEqual("INPUT");
expect(DOM.nodeName(c.componentRenderElement).toUpperCase()).toEqual("DIV");
expect(c.injector.getOptional).toBeTruthy();
expect((<Injector>c.injector).get).toBeTruthy();
expect(c.source).toContain(":0:7");
expect(c.context).toBe(fixture.debugElement.componentInstance);
expect(c.locals["local"]).toBeDefined();
@@ -1485,7 +1486,7 @@ function declareTests(isJit: boolean) {
var c = e.context;
expect(DOM.nodeName(c.renderNode).toUpperCase()).toEqual("SPAN");
expect(DOM.nodeName(c.componentRenderElement).toUpperCase()).toEqual("DIV");
expect(c.injector.getOptional).toBeTruthy();
expect((<Injector>c.injector).get).toBeTruthy();
expect(c.context).toBe(fixture.debugElement.componentInstance);
expect(c.locals["local"]).toBeDefined();
}
@@ -1950,9 +1951,10 @@ class DynamicViewport {
var myService = new MyService();
myService.greeting = 'dynamic greet';
var bindings = Injector.resolve([provide(MyService, {useValue: myService})]);
var injector = ReflectiveInjector.resolveAndCreate([provide(MyService, {useValue: myService})],
vc.injector);
this.done = compiler.resolveComponent(ChildCompUsingService)
.then((compFactory) => {vc.createComponent(compFactory, 0, bindings)});
.then((componentFactory) => vc.createComponent(componentFactory, 0, injector));
}
}
@@ -19,7 +19,7 @@ import {
JSONPBackend,
JSONPBackend_
} from 'angular2/src/http/backends/jsonp_backend';
import {provide, Injector} from 'angular2/core';
import {provide, Injector, ReflectiveInjector} from 'angular2/core';
import {isPresent, StringWrapper} from 'angular2/src/facade/lang';
import {TimerWrapper} from 'angular2/src/facade/async';
import {Request} from 'angular2/src/http/static_request';
@@ -71,7 +71,7 @@ export function main() {
let sampleRequest: Request;
beforeEach(() => {
let injector = Injector.resolveAndCreate([
let injector = ReflectiveInjector.resolveAndCreate([
provide(ResponseOptions, {useClass: BaseResponseOptions}),
provide(BrowserJsonp, {useClass: MockBrowserJsonp}),
provide(JSONPBackend, {useClass: JSONPBackend_})
@@ -14,7 +14,7 @@ import {
import {ObservableWrapper} from 'angular2/src/facade/async';
import {BrowserXhr} from 'angular2/src/http/backends/browser_xhr';
import {MockConnection, MockBackend} from 'angular2/src/http/backends/mock_backend';
import {provide, Injector} from 'angular2/core';
import {provide, Injector, ReflectiveInjector} from 'angular2/core';
import {Request} from 'angular2/src/http/static_request';
import {Response} from 'angular2/src/http/static_response';
import {Headers} from 'angular2/src/http/headers';
@@ -34,7 +34,7 @@ export function main() {
var sampleResponse2: Response;
beforeEach(() => {
var injector = Injector.resolveAndCreate(
var injector = ReflectiveInjector.resolveAndCreate(
[provide(ResponseOptions, {useClass: BaseResponseOptions}), MockBackend]);
backend = injector.get(MockBackend);
var base = new BaseRequestOptions();
@@ -14,7 +14,7 @@ import {
import {ObservableWrapper} from 'angular2/src/facade/async';
import {BrowserXhr} from 'angular2/src/http/backends/browser_xhr';
import {XHRConnection, XHRBackend} from 'angular2/src/http/backends/xhr_backend';
import {provide, Injector} from 'angular2/core';
import {provide, Injector, ReflectiveInjector} from 'angular2/core';
import {Request} from 'angular2/src/http/static_request';
import {Response} from 'angular2/src/http/static_response';
import {Headers} from 'angular2/src/http/headers';
@@ -86,7 +86,7 @@ export function main() {
var sampleRequest: Request;
beforeEach(() => {
var injector = Injector.resolveAndCreate([
var injector = ReflectiveInjector.resolveAndCreate([
provide(ResponseOptions, {useClass: BaseResponseOptions}),
provide(BrowserXhr, {useClass: MockBrowserXHR}),
XHRBackend
+5 -5
View File
@@ -10,7 +10,7 @@ import {
it,
xit
} from 'angular2/testing_internal';
import {Injector, provide} from 'angular2/core';
import {Injector, provide, ReflectiveInjector} from 'angular2/core';
import {MockBackend, MockConnection} from 'angular2/src/http/backends/mock_backend';
import {
BaseRequestOptions,
@@ -35,15 +35,15 @@ export function main() {
describe('injectables', () => {
var url = 'http://foo.bar';
var http: Http;
var parentInjector: Injector;
var childInjector: Injector;
var parentInjector: ReflectiveInjector;
var childInjector: ReflectiveInjector;
var jsonpBackend: MockBackend;
var xhrBackend: MockBackend;
var jsonp: Jsonp;
it('should allow using jsonpInjectables and httpInjectables in same injector',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
parentInjector = Injector.resolveAndCreate([
parentInjector = ReflectiveInjector.resolveAndCreate([
provide(XHRBackend, {useClass: MockBackend}),
provide(JSONPBackend, {useClass: MockBackend})
]);
@@ -94,7 +94,7 @@ export function main() {
var baseResponse: Response;
var jsonp: Jsonp;
beforeEach(() => {
injector = Injector.resolveAndCreate([
injector = ReflectiveInjector.resolveAndCreate([
BaseRequestOptions,
MockBackend,
provide(
@@ -1,5 +1,5 @@
import 'package:angular2/testing_internal.dart' show SpyObject;
import 'package:angular2/core.dart' show Injector, bind;
import 'package:angular2/core.dart' show Injector, ReflectiveInjector, bind;
import 'package:angular2/src/core/application_ref.dart' show ApplicationRef;
import 'package:angular2/src/core/linker/component_factory.dart'
show ComponentRef;
@@ -15,7 +15,7 @@ class SpyComponentRef extends SpyObject implements ComponentRef {
Injector injector;
SpyComponentRef() {
this.injector = Injector
this.injector = ReflectiveInjector
.resolveAndCreate([bind(ApplicationRef).toClass(SpyApplicationRef)]);
}
}
@@ -1,5 +1,5 @@
import {SpyObject} from 'angular2/testing_internal';
import {Injector, provide} from 'angular2/core';
import {ReflectiveInjector, provide} from 'angular2/core';
import {global} from 'angular2/src/facade/lang';
import {ApplicationRef, ApplicationRef_} from 'angular2/src/core/application_ref';
@@ -11,8 +11,8 @@ export class SpyComponentRef extends SpyObject {
injector;
constructor() {
super();
this.injector =
Injector.resolveAndCreate([provide(ApplicationRef, {useClass: SpyApplicationRef})]);
this.injector = ReflectiveInjector.resolveAndCreate(
[provide(ApplicationRef, {useClass: SpyApplicationRef})]);
}
}
+6 -5
View File
@@ -169,7 +169,7 @@ var NG_CORE = [
'PLATFORM_PIPES',
'DebugNode',
'DebugElement',
'Dependency',
'ReflectiveDependency',
'DependencyMetadata',
'Directive',
'DirectiveMetadata',
@@ -194,10 +194,11 @@ var NG_CORE = [
'Injectable',
'InjectableMetadata',
'Injector',
'ReflectiveInjector',
'InstantiationError',
'InvalidProviderError',
'IterableDiffers',
'Key',
'ReflectiveKey',
'KeyValueChangeRecord',
'KeyValueDiffers',
'NgZone',
@@ -219,9 +220,9 @@ var NG_CORE = [
'Renderer',
'RootRenderer',
'RenderComponentType',
'ResolvedBinding:dart',
'ResolvedProvider:dart',
'ResolvedFactory',
'ResolvedReflectiveBinding:dart',
'ResolvedReflectiveProvider:dart',
'ResolvedReflectiveFactory',
'Self',
'SelfMetadata',
'SkipSelf',
@@ -143,7 +143,8 @@ export class RedirectToParentCmp {
@RouteConfig([new Route({path: '/', component: HelloCmp})])
export class DynamicLoaderCmp {
private _componentRef: ComponentRef = null;
@ViewChild('viewport', {read: ViewContainerRef}) private _viewport: ViewContainerRef;
@ViewChild('viewport', {read: ViewContainerRef}) viewport: ViewContainerRef;
constructor(private _dynamicComponentLoader: DynamicComponentLoader) {}
@@ -152,8 +153,7 @@ export class DynamicLoaderCmp {
this._componentRef.destroy();
this._componentRef = null;
}
return this._dynamicComponentLoader.loadNextToLocation(DynamicallyLoadedComponent,
this._viewport)
return this._dynamicComponentLoader.loadNextToLocation(DynamicallyLoadedComponent, viewport)
.then((cmp) => { this._componentRef = cmp; });
}
}
@@ -12,7 +12,7 @@ import {
SpyObject
} from 'angular2/testing_internal';
import {Injector, provide} from 'angular2/core';
import {Injector, provide, ReflectiveInjector} from 'angular2/core';
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {Location, LocationStrategy, APP_BASE_HREF} from 'angular2/platform/common';
@@ -26,7 +26,7 @@ export function main() {
function makeLocation(baseHref: string = '/my/app', provider: any = CONST_EXPR([])): Location {
locationStrategy = new MockLocationStrategy();
locationStrategy.internalBaseHref = baseHref;
let injector = Injector.resolveAndCreate(
let injector = ReflectiveInjector.resolveAndCreate(
[Location, provide(LocationStrategy, {useValue: locationStrategy}), provider]);
return location = injector.get(Location);
}