feat(injector): change injector to recover from errors

So it can instantiate an object after a failed attempt.
This commit is contained in:
vsavkin 2014-10-09 11:03:36 -04:00
parent b9d03e6635
commit 9b411372df
2 changed files with 29 additions and 4 deletions

View File

@ -94,6 +94,14 @@ export class Injector {
if (this._bindings.length <= key.id) return null;
return ListWrapper.get(this._bindings, key.id);
}
_markAsConstructing(key:Key) {
this._setInstance(key, _constructing);
}
_clear(key:Key) {
this._setInstance(key, null);
}
}
@ -125,7 +133,7 @@ class _SyncInjectorStrategy {
if (binding.providedAsFuture) throw new AsyncBindingError(key);
//add a marker so we can detect cyclic dependencies
this.injector._setInstance(key, _constructing);
this.injector._markAsConstructing(key);
var deps = this._resolveDependencies(key, binding);
return this._createInstance(key, binding, deps);
@ -136,7 +144,7 @@ class _SyncInjectorStrategy {
var getDependency = d => this.injector._getByKey(d.key, d.asFuture, d.lazy);
return ListWrapper.map(binding.dependencies, getDependency);
} catch (e) {
this.injector._setInstance(key, null);
this.injector._clear(key);
if (e instanceof ProviderError) e.addKey(key);
throw e;
}
@ -148,6 +156,7 @@ class _SyncInjectorStrategy {
this.injector._setInstance(key, instance);
return instance;
} catch (e) {
this.injector._clear(key);
throw new InstantiationError(e, key);
}
}
@ -182,7 +191,7 @@ class _AsyncInjectorStrategy {
if (isBlank(binding)) return null;
//add a marker so we can detect cyclic dependencies
this.injector._setInstance(key, _constructing);
this.injector._markAsConstructing(key);
var deps = this._resolveDependencies(key, binding);
var depsFuture = FutureWrapper.wait(deps);
@ -200,7 +209,7 @@ class _AsyncInjectorStrategy {
var getDependency = d => this.injector._getByKey(d.key, true, d.lazy);
return ListWrapper.map(binding.dependencies, getDependency);
} catch (e) {
this.injector._setInstance(key, null);
this.injector._clear(key);
if (e instanceof ProviderError) e.addKey(key);
throw e;
}
@ -217,6 +226,7 @@ class _AsyncInjectorStrategy {
if (!_isWaiting(instance)) return instance;
return binding.factory(deps);
} catch (e) {
this.injector._clear(key);
throw new InstantiationError(e, key);
}
}

View File

@ -176,6 +176,21 @@ export function main() {
}
});
it('should instantiate an object after a failed attempt', function () {
var isBroken = true;
var injector = new Injector([
Car,
bind(Engine).toFactory([], () => isBroken ? new BrokenEngine() : new Engine())
]);
expect(() => injector.get(Car)).toThrow();
isBroken = false;
expect(injector.get(Car)).toBeAnInstanceOf(Car);
});
describe("child", function () {
it('should load instances from parent injector', function () {