| OLD | NEW |
| (Empty) | |
| 1 part of di; |
| 2 |
| 3 class Injector { |
| 4 |
| 5 /** |
| 6 * Name of the injector or null of none is given. |
| 7 */ |
| 8 final String name; |
| 9 |
| 10 static const List<Type> _PRIMITIVE_TYPES = const <Type>[ |
| 11 num, int, double, String, bool |
| 12 ]; |
| 13 |
| 14 /** |
| 15 * Returns the parent injector or null if root. |
| 16 */ |
| 17 final Injector parent; |
| 18 |
| 19 Injector _root; |
| 20 |
| 21 Map<Type, _Provider> _providers = <Type, _Provider>{}; |
| 22 |
| 23 final Map<Type, Object> instances = <Type, Object>{}; |
| 24 |
| 25 final List<Type> resolving = <Type>[]; |
| 26 |
| 27 final bool allowImplicitInjection; |
| 28 |
| 29 Iterable<Type> _typesCache; |
| 30 |
| 31 /** |
| 32 * List of all types which the injector can return |
| 33 */ |
| 34 Iterable<Type> get _types { |
| 35 if (_typesCache == null) { |
| 36 _typesCache = _providers.keys; |
| 37 } |
| 38 return _typesCache; |
| 39 } |
| 40 |
| 41 Injector({List<Module> modules, String name, |
| 42 bool allowImplicitInjection: false}) |
| 43 : this.fromParent(modules, null, |
| 44 name: name, allowImplicitInjection: allowImplicitInjection); |
| 45 |
| 46 Injector.fromParent(List<Module> modules, |
| 47 Injector this.parent, {this.name, this.allowImplicitInjection}) { |
| 48 _root = parent == null ? this : parent._root; |
| 49 if (modules != null) { |
| 50 modules.forEach((module) { |
| 51 _providers.addAll(module._bindings); |
| 52 }); |
| 53 } |
| 54 _providers[Injector] = new _ValueProvider(this); |
| 55 } |
| 56 |
| 57 Injector get root => _root; |
| 58 |
| 59 Set<Type> get types { |
| 60 var types = new Set.from(_types); |
| 61 var parent = this.parent; |
| 62 while (parent != null) { |
| 63 types.addAll(parent._types); |
| 64 parent = parent.parent; |
| 65 } |
| 66 return types; |
| 67 } |
| 68 |
| 69 String _error(message, [appendDependency]) { |
| 70 if (appendDependency != null) { |
| 71 resolving.add(appendDependency); |
| 72 } |
| 73 |
| 74 String graph = resolving.join(' -> '); |
| 75 |
| 76 resolving.clear(); |
| 77 |
| 78 return '$message (resolving $graph)'; |
| 79 } |
| 80 |
| 81 dynamic _getInstanceByType(Type typeName, Injector requester) { |
| 82 _checkTypeConditions(typeName); |
| 83 |
| 84 if (resolving.contains(typeName)) { |
| 85 throw new CircularDependencyError( |
| 86 _error('Cannot resolve a circular dependency!', typeName)); |
| 87 } |
| 88 |
| 89 var providerWithInjector = _getProviderWithInjectorForType(typeName); |
| 90 var provider = providerWithInjector.provider; |
| 91 var injector = providerWithInjector.injector; |
| 92 var visible = provider.visibility != null ? |
| 93 provider.visibility(requester, injector) : |
| 94 _defaultVisibility(requester, injector); |
| 95 |
| 96 if (visible && instances.containsKey(typeName)) { |
| 97 return instances[typeName]; |
| 98 } |
| 99 |
| 100 if (providerWithInjector.injector != this || !visible) { |
| 101 if (!visible) { |
| 102 if (injector.parent == null) { |
| 103 throw new NoProviderError( |
| 104 _error('No provider found for ${typeName}!', typeName)); |
| 105 } |
| 106 injector = |
| 107 injector.parent._getProviderWithInjectorForType(typeName).injector; |
| 108 } |
| 109 return injector._getInstanceByType(typeName, requester); |
| 110 } |
| 111 |
| 112 var value; |
| 113 try { |
| 114 var strategy = provider.creationStrategy != null ? |
| 115 provider.creationStrategy : _defaultCreationStrategy; |
| 116 value = strategy(requester, injector, () { |
| 117 resolving.add(typeName); |
| 118 var val = provider.get(this, requester, _getInstanceByType, _error); |
| 119 resolving.removeLast(); |
| 120 return val; |
| 121 }); |
| 122 } catch(e) { |
| 123 resolving.clear(); |
| 124 rethrow; |
| 125 } |
| 126 |
| 127 // cache the value. |
| 128 providerWithInjector.injector.instances[typeName] = value; |
| 129 return value; |
| 130 } |
| 131 |
| 132 /// Returns a pair for provider and the injector where it's defined. |
| 133 _ProviderWithDefiningInjector _getProviderWithInjectorForType(Type typeName) { |
| 134 if (_providers.containsKey(typeName)) { |
| 135 return new _ProviderWithDefiningInjector(_providers[typeName], this); |
| 136 } |
| 137 |
| 138 if (parent != null) { |
| 139 return parent._getProviderWithInjectorForType(typeName); |
| 140 } |
| 141 |
| 142 if (allowImplicitInjection) { |
| 143 return new _ProviderWithDefiningInjector( |
| 144 new _TypeProvider(typeName), this); |
| 145 } |
| 146 |
| 147 throw new NoProviderError(_error('No provider found for ' |
| 148 '${typeName}!', typeName)); |
| 149 } |
| 150 |
| 151 void _checkTypeConditions(Type typeName) { |
| 152 if (_PRIMITIVE_TYPES.contains(typeName)) { |
| 153 throw new NoProviderError(_error('Cannot inject a primitive type ' |
| 154 'of $typeName!', typeName)); |
| 155 } |
| 156 } |
| 157 |
| 158 |
| 159 // PUBLIC API |
| 160 |
| 161 /** |
| 162 * Get an instance for given token ([Type]). |
| 163 * |
| 164 * If the injector already has an instance for this token, it returns this |
| 165 * instance. Otherwise, injector resolves all its dependencies, instantiate |
| 166 * new instance and returns this instance. |
| 167 * |
| 168 * If there is no binding for given token, injector asks parent injector. |
| 169 * |
| 170 * If there is no parent injector, an implicit binding is used. That is, |
| 171 * the token ([Type]) is instantiated. |
| 172 */ |
| 173 dynamic get(Type type) => _getInstanceByType(type, this); |
| 174 |
| 175 /** |
| 176 * Create a child injector. |
| 177 * |
| 178 * Child injector can override any bindings by adding additional modules. |
| 179 * |
| 180 * It also accepts a list of tokens that a new instance should be forced. |
| 181 * That means, even if some parent injector already has an instance for this |
| 182 * token, there will be a new instance created in the child injector. |
| 183 */ |
| 184 Injector createChild(List<Module> modules, |
| 185 {List<Type> forceNewInstances, String name}) { |
| 186 if (forceNewInstances != null) { |
| 187 Module forceNew = new Module(); |
| 188 forceNewInstances.forEach((type) { |
| 189 var providerWithInjector = _getProviderWithInjectorForType(type); |
| 190 var provider = providerWithInjector.provider; |
| 191 forceNew.factory(type, |
| 192 (Injector inj) => provider.get(this, inj, inj._getInstanceByType, |
| 193 inj._error), |
| 194 creation: provider.creationStrategy, |
| 195 visibility: provider.visibility); |
| 196 }); |
| 197 |
| 198 modules = modules.toList(); // clone |
| 199 modules.add(forceNew); |
| 200 } |
| 201 |
| 202 return newFromParent(modules, name); |
| 203 } |
| 204 |
| 205 newFromParent(List<Module> modules, String name) { |
| 206 throw new UnimplementedError('This method must be overriden.'); |
| 207 } |
| 208 |
| 209 Object newInstanceOf(Type type, ObjectFactory factory, Injector requestor, |
| 210 errorHandler(message, [appendDependency])) { |
| 211 throw new UnimplementedError('This method must be overriden.'); |
| 212 } |
| 213 } |
| 214 |
| 215 class _ProviderWithDefiningInjector { |
| 216 final _Provider provider; |
| 217 final Injector injector; |
| 218 _ProviderWithDefiningInjector(this.provider, this.injector); |
| 219 } |
| OLD | NEW |