UPDATE!!!
A new method has just been added to IObjectFactory committed on spring actionscript svn repo in order to let autowire non visual classes!! w00t!:)
Take a look at
IObjectFactory.createInstance(clazz:Class, constructorArguments:Array = null):*;
this solves the problem and we have no longer to extend AutowiringObjectBase
Take a look to the commit http://bit.ly/dmhZWd and update your source
Thanx Roland to have done the whole work
and for the support
—————
First of all a little explanation on the title of this post:
I’m having some fun with spring actionscript, an as3 IoC framework. It’s my first experience with inversion of control in actionscript and I found it a little weird at first, but now I (think I’ve) understood how it works I’m having really lots of fun with it
.
Anyway, Spring actionscript provides two ways of autowiring object properties:
- for non visual objects: you define your object and its properties in the context (xml or mxml) and when that object is being created the framework automatically wires up all its properties driving into each of them the defined value.
- for visual objects: you mark your component’s properties with the custom metatag [Autowired] and when your component is added to the display list spring actionscript automatically wires up all marked properties.
But what if I want to create a non visual object at runtime and I want the framework to autowire its marked properties?
I created a base class in order to do that, it’s built upon the pureMVC extension for spring actionscript, which is actually the microarchitecture framework I’m using right now.
Here’s the code:
package
{
import flash.utils.describeType;
import org.as3commons.lang.ClassUtils;
import org.puremvc.as3.patterns.facade.Facade;
import org.springextensions.actionscript.context.IConfigurableApplicationContext;
import org.springextensions.actionscript.puremvc.interfaces.IIocFacade;
/**
* This class provides autowiring for subclasses.
*
* @author pigiuz
*
*/
public class AutowiringObjectBase
{
private var _iocFacade:IIocFacade;
public function AutowiringObjectBase()
{
_iocFacade = Facade.getInstance() as IIocFacade;
autoWire();
}
private function get container():IConfigurableApplicationContext
{
return _iocFacade.container;
}
private function autoWire():void
{
var typeDescription:XML = describeType(this);
for each (var metaDataNode:XML in typeDescription..metadata)
{
if (metaDataNode.attribute("name") == "Autowired")
{
var host:String;
var chain:String;
var propertyNode:XML = metaDataNode.parent();
var property:String = propertyNode.@name.toString();
trace("Found Autowired property: " + property);
var objectName:String = property;
var autowireByType:Boolean = true;
for each (var arg:XML in metaDataNode.arg)
{
if (arg.attribute("key") == "host")
{
host = arg.attribute("value")
}
else if (arg.attribute("key") == "chain")
{
chain = arg.attribute("value");
}
else if (arg.attribute("value") == "byName")
{
autowireByType = false;
}
}
if (autowireByType)
{
if (host && chain)
{
// CHAINED AUTOWIRE
trace("Autowiring: " + property + " in " + this + " from " + host + "." + chain);
var hostObject:Object = container.getObject(host);
if (hostObject)
{
this[property] = hostObject[chain];
}
}
else
{
// AUTOWIRE BY TYPE
var clazz:Class = ClassUtils.forName(propertyNode.@type.toString());
var objectNames:Array = container.getObjectNamesForType(clazz);
if (objectNames.length == 1)
{
objectName = objectNames[0];
}
trace("Autowiring by type: " + property + " in " + this);
this[property] = container.getObject(objectName);
}
}
else
{
// AUTOWIRE BY NAME
trace("Autowiring by name:" + property + " in " + this);
this[property] = container.getObject(objectName);
}
propertyNode = null;
host = null;
chain = null;
}
metaDataNode = null;
}
// dispose describetype
typeDescription = null;
}
}
}
As you can see, as the constructor is called the iocFacade (the puremvc’s facade decorated in a springy fashion) is retrieved in order to be able to locate the application context (iocFacade is not needed if you are not using puremvc, just make sure you can locate the context otherwise it won’t work!) and the autoWire method is called.
Basically what autoWire() does is checking which properties are marked as [Autowired] and looking up the container for object definitions satisfying required conditions (name\type\host-chain), then wire each property with the found object.
Good thing is in order to leverage this autowiring capability you just have extend this class and create your own classes feeling free to mark properties as [Autowired].
Is there some better solution out there?
Tags: IoC, PureMVC, Spring Actionscript