From 9b411372df3471e7119738b57ac9c17636fe7990 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 9 Oct 2014 11:03:36 -0400 Subject: [PATCH] feat(injector): change injector to recover from errors So it can instantiate an object after a failed attempt. --- modules/di/src/injector.js | 18 ++++++++++++++---- modules/di/test/di/injector_spec.js | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/modules/di/src/injector.js b/modules/di/src/injector.js index f5e281f72f..1f7dcba372 100644 --- a/modules/di/src/injector.js +++ b/modules/di/src/injector.js @@ -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); } } diff --git a/modules/di/test/di/injector_spec.js b/modules/di/test/di/injector_spec.js index 135ffa8cd6..d46dfe706a 100644 --- a/modules/di/test/di/injector_spec.js +++ b/modules/di/test/di/injector_spec.js @@ -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 () {