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: , ,

Leave a Reply