Permalink
Browse files

Changes the injector's behavior to automatically create instances of …

…unmapped classes when they're requested as dependencies while still throwing for unmapped interfaces


Fixes #36
  • Loading branch information...
1 parent 4f3ed47 commit b332ba2cc292e787b0a7f10a7449e57b3da01f5b @tschneidereit committed Jun 2, 2012
@@ -14,6 +14,8 @@ package org.swiftsuspenders.injection
import flash.utils.Dictionary;
import flash.utils.getQualifiedClassName;
+ import org.swiftsuspenders.injection.dependencyproviders.ClassProvider;
+
import org.swiftsuspenders.injection.dependencyproviders.DependencyProvider;
import org.swiftsuspenders.injection.dependencyproviders.LocalOnlyProvider;
import org.swiftsuspenders.injection.dependencyproviders.SoftDependencyProvider;
@@ -171,6 +173,7 @@ package org.swiftsuspenders.injection
private var _classDescriptor : TypeDescriptor;
private var _mappings : Dictionary;
private var _mappingsInProcess : Dictionary;
+ private var _defaultProviders : Dictionary;
private var _managedObjects : Dictionary;
private var _reflector : Reflector;
@@ -184,6 +187,7 @@ package org.swiftsuspenders.injection
{
_mappings = new Dictionary();
_mappingsInProcess = new Dictionary();
+ _defaultProviders = new Dictionary();
_managedObjects = new Dictionary();
try
{
@@ -532,7 +536,29 @@ package org.swiftsuspenders.injection
}
injector = injector.parentInjector;
}
- return softProvider;
+ return softProvider || getDefaultProvider(mappingId);
+ }
+
+ SsInternal function getDefaultProvider(mappingId : String) : DependencyProvider
+ {
+ //No meaningful way to automatically create Strings
+ if (mappingId === 'String|')
+ {
+ return null;
+ }
+ const parts : Array = mappingId.split('|');
+ const name : String = parts.pop();
+ if (name.length !== 0)
+ {
+ return null;
+ }
+ const type : Class = Class(_applicationDomain.getDefinition(parts.pop()));
+ var description : TypeDescription = _classDescriptor.getDescription(type);
+ if (!description.ctor)
+ {
+ return null;
+ }
+ return (_defaultProviders[type] ||= new ClassProvider(type));
}
@@ -8,6 +8,7 @@
package org.swiftsuspenders.typedescriptions
{
import flash.utils.Dictionary;
+ import flash.utils.getQualifiedClassName;
import org.swiftsuspenders.injection.Injector;
import org.swiftsuspenders.injection.InjectorError;
@@ -44,7 +45,8 @@ package org.swiftsuspenders.typedescriptions
}
throw(new InjectorError(
'Injector is missing a mapping to handle injection into property "' +
- _propertyName + '" of object "' + target + '" with type "' + targetType +
+ _propertyName + '" of object "' + target + '" with type "' +
+ getQualifiedClassName(targetType) +
'". Target dependency: "' + _mappingId + '"'));
}
target[_propertyName] = provider.apply(targetType, injector, injectParameters);
@@ -23,6 +23,7 @@ package org.swiftsuspenders
import org.swiftsuspenders.support.injectees.childinjectors.RobotLeg;
import org.swiftsuspenders.support.injectees.childinjectors.RobotToes;
import org.swiftsuspenders.support.types.Clazz;
+ import org.swiftsuspenders.support.types.Interface;
import org.swiftsuspenders.utils.SsInternal;
use namespace SsInternal;
@@ -161,8 +162,9 @@ package org.swiftsuspenders
{
var childInjector : Injector = injector.createChildInjector();
- Assert.assertFalse('Child injector should not return true for hasMapping that does not exists on parent injector',
- childInjector.satisfies(Clazz));
+ Assert.assertFalse('Child injector should not return true for hasMapping that does ' +
+ 'not exists on parent injector',
+ childInjector.satisfies(Interface));
}
[Test]
@@ -88,20 +88,14 @@ package org.swiftsuspenders
}
[Test]
- public function unbind():void
+ public function unbindRemovesMapping():void
{
- var injectee:ClassInjectee = new ClassInjectee();
+ var injectee:InterfaceInjectee = new InterfaceInjectee();
var value:Clazz = new Clazz();
- injector.map(Clazz).toValue(value);
- injector.unmap(Clazz);
- try
- {
- injector.injectInto(injectee);
- }
- catch(e:Error)
- {
- }
- Assert.assertEquals("Property should not be injected", null, injectee.property);
+ injector.map(Interface).toValue(value);
+ Assert.assertTrue(injector.satisfies(Interface));
+ injector.unmap(Interface);
+ Assert.assertFalse(injector.satisfies(Interface));
}
[Test]
@@ -441,18 +435,18 @@ package org.swiftsuspenders
Assert.assertEquals("Instance field 'property1' should be identical to Instance field 'namedProperty2'", injectee.property1, injectee.namedProperty2);
}
- [Test]
- public function performInjectionIntoValueWithRecursiveSingeltonDependency():void
- {
- var valueInjectee : InterfaceInjectee = new InterfaceInjectee();
- injector.map(InterfaceInjectee).toValue(valueInjectee);
- injector.map(Interface).toSingleton(RecursiveInterfaceInjectee);
-
- injector.injectInto(valueInjectee);
+// [Test]
+// public function performInjectionIntoValueWithRecursiveSingletonDependency():void
+// {
+// var valueInjectee : InterfaceInjectee = new InterfaceInjectee();
+// injector.map(InterfaceInjectee).toValue(valueInjectee);
+// injector.map(Interface).toSingleton(RecursiveInterfaceInjectee);
+//
+// injector.injectInto(valueInjectee);
// Assert.assertEquals("Instance field 'property1' should be identical to Instance field 'property2'", injectee.property1, injectee.property2);
// Assert.assertEquals("Instance field 'property1' should be identical to Instance field 'namedProperty1'", injectee.property1, injectee.namedProperty1);
// Assert.assertEquals("Instance field 'property1' should be identical to Instance field 'namedProperty2'", injectee.property1, injectee.namedProperty2);
- }
+// }
[Test]
public function injectXMLValue() : void
@@ -461,14 +455,22 @@ package org.swiftsuspenders
var value : XML = <test/>;
injector.map(XML).toValue(value);
injector.injectInto(injectee);
- Assert.assertEquals('injected value should be indentical to mapped value', injectee.property, value);
+ Assert.assertEquals('injected value should be indentical to mapped value',
+ injectee.property, value);
}
[Test(expects="org.swiftsuspenders.injection.InjectorError")]
- public function haltOnMissingDependency():void
+ public function haltOnMissingInterfaceDependency():void
{
- var injectee:InterfaceInjectee = new InterfaceInjectee();
+ injector.injectInto(new InterfaceInjectee());
+ }
+
+ [Test]
+ public function UseDefaultInjectorForUnmappedDependency():void
+ {
+ const injectee : ClassInjectee = new ClassInjectee();
injector.injectInto(injectee);
+ assertThat(injectee.property, isA(Clazz));
}
[Test(expects="org.swiftsuspenders.injection.InjectorError")]
@@ -508,9 +510,15 @@ package org.swiftsuspenders
}
[Test]
- public function hasMappingFailsForUnmappedUnnamedClass():void
+ public function satisfiesFailsForUnmappedUnnamedInterface():void
+ {
+ Assert.assertFalse(injector.satisfies(Interface));
+ }
+
+ [Test]
+ public function satisfiesSucceedsForUnmappedUnnamedClass():void
{
- Assert.assertFalse(injector.satisfies(Clazz));
+ Assert.assertTrue(injector.satisfies(Clazz));
}
[Test]
@@ -536,7 +544,7 @@ package org.swiftsuspenders
[Test(expects="org.swiftsuspenders.injection.InjectorError")]
public function getMappingResponseFailsForUnmappedNamedClass():void
{
- Assert.assertNull(injector.getInstance(Clazz, 'namedClass'));
+ injector.getInstance(Clazz, 'namedClass');
}
[Test]
@@ -585,7 +593,7 @@ package org.swiftsuspenders
{
var injectee : OptionalOneRequiredParameterMethodInjectee =
injector.getInstance(OptionalOneRequiredParameterMethodInjectee);
- Assert.assertNull("injectee mustn\'t contain Clazz instance", injectee.getDependency());
+ Assert.assertNull("injectee mustn\'t contain Interface instance", injectee.getDependency());
}
[Test]
@@ -1,17 +1,17 @@
/*
- * Copyright (c) 2011 the original author or authors
+ * Copyright (c) 2012 the original author or authors
*
* Permission is hereby granted to use, modify, and distribute this file
* in accordance with the terms of the license agreement accompanying it.
*/
package org.swiftsuspenders.support.injectees
{
- import org.swiftsuspenders.support.types.Clazz;
+ import org.swiftsuspenders.support.types.Interface;
public class OptionalClassInjectee
{
[Inject(optional=true)]
- public var property:Clazz;
+ public var property:Interface;
}
}
@@ -1,24 +1,24 @@
/*
- * Copyright (c) 2011 the original author or authors
+ * Copyright (c) 2012 the original author or authors
*
* Permission is hereby granted to use, modify, and distribute this file
* in accordance with the terms of the license agreement accompanying it.
*/
package org.swiftsuspenders.support.injectees
{
- import org.swiftsuspenders.support.types.Clazz;
+ import org.swiftsuspenders.support.types.Interface;
public class OptionalOneRequiredParameterMethodInjectee
{
- private var m_dependency : Clazz;
+ private var m_dependency : Interface;
[Inject(optional=true)]
- public function setDependency(dependency:Clazz):void
+ public function setDependency(dependency:Interface):void
{
m_dependency = dependency;
}
- public function getDependency() : Clazz
+ public function getDependency() : Interface
{
return m_dependency;
}
@@ -1,35 +1,20 @@
/*
-* Copyright (c) 2009 the original author or authors
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*/
+ * Copyright (c) 2012 the original author or authors
+ *
+ * Permission is hereby granted to use, modify, and distribute this file
+ * in accordance with the terms of the license agreement accompanying it.
+ */
package org.swiftsuspenders.support.injectees
{
- import org.swiftsuspenders.support.types.Clazz;
-
+ import org.swiftsuspenders.support.types.Interface;
+
public class TwoOptionalParametersConstructorInjectee
{
- private var m_dependency : Clazz;
+ private var m_dependency : Interface;
private var m_dependency2 : String;
- public function getDependency() : Clazz
+ public function getDependency() : Interface
{
return m_dependency;
}
@@ -38,7 +23,7 @@ package org.swiftsuspenders.support.injectees
return m_dependency2;
}
- public function TwoOptionalParametersConstructorInjectee(dependency:Clazz = null, dependency2:String = null)
+ public function TwoOptionalParametersConstructorInjectee(dependency:Interface = null, dependency2:String = null)
{
m_dependency = dependency;
m_dependency2 = dependency2;
@@ -8,10 +8,14 @@
package org.swiftsuspenders.typedescriptions
{
import org.flexunit.Assert;
+ import org.hamcrest.assertThat;
+ import org.hamcrest.core.isA;
+ import org.hamcrest.object.equalTo;
import org.swiftsuspenders.injection.Injector;
import org.swiftsuspenders.support.injectees.TwoOptionalParametersConstructorInjectee;
import org.swiftsuspenders.support.injectees.TwoParametersConstructorInjectee;
import org.swiftsuspenders.support.types.Clazz;
+ import org.swiftsuspenders.support.types.Interface;
import org.swiftsuspenders.utils.SsInternal;
use namespace SsInternal;
@@ -55,35 +59,35 @@ package org.swiftsuspenders.typedescriptions
[Test]
public function injectionOfFirstOptionalPropertyIntoTwoOptionalParametersConstructor():void
{
- injector.map(Clazz).toSingleton(Clazz);
+ injector.map(Interface).toSingleton(Clazz);
- var parameters : Array = ["org.swiftsuspenders.support.types::Clazz|", "String|"];
+ var parameters : Array = ["org.swiftsuspenders.support.types::Interface|", "String|"];
var injectionPoint:ConstructorInjectionPoint =
new ConstructorInjectionPoint(parameters, 0, null);
var injectee:TwoOptionalParametersConstructorInjectee = injectionPoint.createInstance(
TwoOptionalParametersConstructorInjectee, injector) as TwoOptionalParametersConstructorInjectee;
-
-
- Assert.assertTrue("dependency 1 should be Clazz instance", injectee.getDependency() is Clazz);
- Assert.assertTrue("dependency 2 should be null", injectee.getDependency2() == null);
+
+
+ assertThat(injectee.getDependency(), isA(Clazz));
+ assertThat(injectee.getDependency2(), equalTo(null));
}
[Test]
public function injectionOfSecondOptionalPropertyIntoTwoOptionalParametersConstructor():void
{
injector.map(String).toValue(STRING_REFERENCE);
- var parameters : Array = ["org.swiftsuspenders.support.types::Clazz|", "String|"];
+ var parameters : Array = ["org.swiftsuspenders.support.types::Interface|", "String|"];
var injectionPoint:ConstructorInjectionPoint =
new ConstructorInjectionPoint(parameters, 0, null);
var injectee:TwoOptionalParametersConstructorInjectee = injectionPoint.createInstance(
TwoOptionalParametersConstructorInjectee, injector) as TwoOptionalParametersConstructorInjectee;
- Assert.assertTrue("dependency 1 should be Clazz null", injectee.getDependency() == null);
- Assert.assertTrue("dependency 2 should be null", injectee.getDependency2() == null);
+ assertThat(injectee.getDependency(), equalTo(null));
+ assertThat(injectee.getDependency2(), equalTo(null));
}
}
}
@@ -75,7 +75,7 @@ package org.swiftsuspenders.typedescriptions
{
var injectee:OptionalOneRequiredParameterMethodInjectee =
new OptionalOneRequiredParameterMethodInjectee();
- var parameters : Array = ["org.swiftsuspenders.support.types::Clazz|"];
+ var parameters : Array = ["org.swiftsuspenders.support.types::Interface|"];
var injectionPoint:MethodInjectionPoint =
new MethodInjectionPoint("setDependency", parameters, 1, true, null);
Oops, something went wrong.

0 comments on commit b332ba2

Please sign in to comment.