ActionScript 3

Spring Actionscript : Autowire new instances of non visual objects

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 (nametypehost-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?

Advertisements

3 thoughts on “Spring Actionscript : Autowire new instances of non visual objects

  1. Hey there,

    its also possible to use the [Autowired] metadata on non-visual objects. Just annotate the properties in your class, and only define your object in the XML like this:

    when you instantiate the obhect through the container liek this:
    var o:myClass = applicationContext,getObject(“myObject”);

    your properties will have been injected.

  2. I know I can autowire properties in that way but that approach does not fit to my scenario:

    I need to creare N instances of a class without having to define those objects on context.

    think about this:
    for (var i:int=0;i<n;i++){
    new MyAutowiringClass();
    }
    if MyAutoWiringClass extends AutowiringObjectBase and has some properties marked as [Autowired] those properties are injected automatically and I did not write 1 line of xml on the context.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s