Skip to content
This repository has been archived by the owner on Jul 3, 2019. It is now read-only.

Commit

Permalink
Changes the injector's behavior to automatically create instances of …
Browse files Browse the repository at this point in the history
…unmapped classes when they're requested as dependencies while still throwing for unmapped interfaces

Fixes #36
  • Loading branch information
tschneidereit committed Jun 2, 2012
1 parent 4f3ed47 commit b332ba2
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 78 deletions.
28 changes: 27 additions & 1 deletion src/org/swiftsuspenders/injection/Injector.as
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -184,6 +187,7 @@ package org.swiftsuspenders.injection
{
_mappings = new Dictionary();
_mappingsInProcess = new Dictionary();
_defaultProviders = new Dictionary();
_managedObjects = new Dictionary();
try
{
Expand Down Expand Up @@ -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));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions test/org/swiftsuspenders/ChildInjectorTests.as
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]
Expand Down
64 changes: 36 additions & 28 deletions test/org/swiftsuspenders/InjectorTests.as
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand All @@ -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")]
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading

0 comments on commit b332ba2

Please sign in to comment.