Announcement Announcement Module
Collapse
No announcement yet.
Manual Configuration, and existing instances Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Manual Configuration, and existing instances

    Hi,

    I'm trying to configure Spring ActionScript manually (ie, without XML), but having some trouble getting existing instances into an ObjectFactory. More specifically, I'm trying to write an adapter so that I can use Spring with my current framework, and am struggling with the bindValue part. This is what I've got going so far. Any advice would be greatly appreciated.

    Code:
    package net.boyblack.robotlegs.adapters
    {
    	import net.boyblack.robotlegs.core.IInjector;
    
    	import org.as3commons.reflect.ClassUtils;
    	import org.as3commons.reflect.Field;
    	import org.as3commons.reflect.MetaData;
    	import org.as3commons.reflect.Type;
    	import org.springextensions.actionscript.ioc.ObjectDefinition;
    	import org.springextensions.actionscript.ioc.factory.support.DefaultListableObjectFactory;
    	import org.springextensions.actionscript.utils.ObjectUtils;
    
    	public class SpringInjector implements IInjector
    	{
    		protected var factory:DefaultListableObjectFactory;
    
    		public function SpringInjector()
    		{
    			factory = new DefaultListableObjectFactory();
    		}
    
    		public function bindValue( whenAskedFor:Class, useValue:Object, named:String = null ):void
    		{
    			var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName( whenAskedFor );
    			var useClassName:String = ObjectUtils.getFullQualifiedClassName( useValue );
    			var objdef:ObjectDefinition = new ObjectDefinition( useClassName );
    			// how to store useValue instance?
    			var key:String = named ? named : whenAskedForClassName;
    			factory.registerObjectDefinition( key, objdef );
    		}
    
    		public function bindClass( whenAskedFor:Class, instantiateClass:Class, named:String = null ):void
    		{
    			var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName( whenAskedFor );
    			var useClassName:String = ClassUtils.getFullyQualifiedName( instantiateClass );
    			var objdef:ObjectDefinition = new ObjectDefinition( useClassName );
    			objdef.isSingleton = false;
    			var key:String = named ? named : whenAskedForClassName;
    			factory.registerObjectDefinition( key, objdef );
    		}
    
    		public function bindSingleton( whenAskedFor:Class, named:String = null ):void
    		{
    			var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName( whenAskedFor );
    			var objdef:ObjectDefinition = new ObjectDefinition( whenAskedForClassName );
    			var key:String = named ? named : whenAskedForClassName;
    			factory.registerObjectDefinition( key, objdef );
    		}
    
    		public function bindSingletonOf( whenAskedFor:Class, useSingletonOf:Class, named:String = null ):void
    		{
    			var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName( whenAskedFor );
    			var useClassName:String = ClassUtils.getFullyQualifiedName( useSingletonOf );
    			var objdef:ObjectDefinition = new ObjectDefinition( useClassName );
    			var key:String = named ? named : whenAskedForClassName;
    			factory.registerObjectDefinition( key, objdef );
    		}
    
    		public function injectInto( target:Object ):void
    		{
    			var type:Type = Type.forInstance( target );
    			var fields:Array = type.fields;
    			for each ( var field:Field in fields )
    			{
    				if ( field.hasMetaData( 'Inject' ) )
    				{
    					var named:String;
    					var mds:Array = field.getMetaData( 'Inject' );
    					for each ( var md:MetaData in mds )
    					{
    						if ( md.hasArgumentWithKey( 'name' ) )
    						{
    							named = md.getArgument( 'name' ).value;
    						}
    						else if ( md.hasArgumentWithKey( 'id' ) )
    						{
    							named = md.getArgument( 'id' ).value;
    						}
    					}
    					named = named ? named : field.type.fullName;
    					target[ field.name ] = factory.getObject( named );
    				}
    			}
    		}
    
    		public function unbind( clazz:Class, named:String = null ):void
    		{
    			named = named ? named : ClassUtils.getFullyQualifiedName( clazz );
    			factory.removeObjectDefinition( named );
    		}
    
    	}
    }

  • #2
    what is the bindValue for?

    Hey there,

    interesting to see how you're using Spring Actionscript in your own framework I'm trying to find out what the bindValue() method actually does though, is this when an instance's property needs to be injected by a managed value?

    cheers,

    Roland

    Comment


    • #3
      Hi Roland,

      Thanks for the response. bindValue is not as complicated as that though; it's simply a way to put an existing instance into the container and re-use it whenever it's needed (singleton scope). It's the same as bindClass, except bindValue works with existing instances, and bindClass will instantiate a new instance each time (prototype scope).

      I've been combing through the docs, but haven't found any easy way to provide existing instances to containers/contexts/factories. Even implementing IFactoryObject doesn't seem to do the trick. I thought of a REALLY nasty way to do it (using static properties), but am pretty sure I would never be allowed to program anything ever again if I released it.

      So, how do I register existing instances with a Spring container?

      Many thanks,
      Shaun

      Comment


      • #4
        not possible right now

        Hi Shaun,

        I can save you a bit of time combing through the documentation, its NOT possible currently to add an instance to the application context. The singleton cache is not exposed to the 'outside world' currently.

        Its an interesting approach you're taking though, so I think we can consider a way of opening the container like this.

        Best way of going about things for you right now is to submit a feature request in JIRA: http://jira.springframework.org/brow...ACTIONSCRIPTAS

        If you have suggestions for implementing you can also attach a patch file with your code.

        Right now we're busy getting the version 0.8 release out of the door, so I'm afraid we won't be adding the functionality very soon, please bear with us.

        cheers,

        Roland

        Comment


        • #5
          Hi Roland,

          Aha! Thanks for letting me know... my hacks were getting pretty gnarly. Perhaps I should check out the source, and see if I can come up with a patch - the problem at this point, however, is my flaky knowledge of Spring and it's philosophies.

          Cheers,
          Shaun

          Comment


          • #6
            I hear ya

            Hey Shaun,

            I know what you're talking about I wanted to get to know Spring AS better as well, so that was the main reason why I joined the team actually I volunteered to do the documentation, which would forced me to go through the entire code base back to front, that was a good way of getting to know what goes where
            Mind you, I'm still not a guru, that's Christophe and Martino, but I'm getting there
            I do recommend you check out the sources, right now we're busy re-structuring the SVN repository, so when you do a checkout make sure you only take the 'trunk' from the root of the repository, the other project directories in the root are all deprecated.
            What you want to sift through first is the FlexXMLApplicationContext or XMLApplicationContext classes and their superclasses, this is the nucleus of the container.

            If you have any questions along the way, feel free to ask them here.

            -Roland

            Comment


            • #7
              Hey Roland,

              Thanks for pointing me in the right direction (especially with regards to the deprecated SVN root folders). I'll take a look into the IApplicationContext implementations and see if I can get anything going. Thanks for all your help

              Cheers,
              Shaun

              Comment


              • #8
                np

                no problem Shaun, please keep us posted on your progress.

                Comment


                • #9
                  did a bit of digging

                  Hey Shaun,

                  I did a little bit of digging for you last night, I think your best route would be to subclass the AbstractXMLObjectFactory (found in the org.springextensions.actionscript.ioc.factory.supp ort package). This class has a protected variable called singletonCache, in your subclass you can write methods that access this dictionary.
                  I don't think this kind of functionality will ever be part of the spring actionscript library itself, since its geared towards a very specific solution so for you it would be the best way to start 'rolling your own' from here.

                  Examine the getObject() method in the same AbstractXMLObjectFactory class to understand better how the singletonCache is being populated.

                  If you need help or info, you know here to find us.

                  cheers,

                  Roland

                  P.S. The field I mentioned used to be private, I changed it to protected only last night, so if you want to be able to pull this off you're gonna need the very latest source from the trunk.
                  Or you can just wait for the version 0.8 release, which will see the light today (hopefully if everything goes according to plan)

                  Comment


                  • #10
                    Above and beyond the call of duty sir! Thanks Roland, you rock. I'll jump in and see what I can put together (didn't get a chance yesterday). Cheers!

                    Comment


                    • #11
                      np

                      glad to help, lemme know how you're faring.

                      later,

                      ROland

                      P.S. Oh, and do check out http://www.springactionscript.org again, its just had a huge update today with the latest version of all the docs.
                      Last edited by 666shooter; Jul 15th, 2009, 11:00 AM. Reason: added URL

                      Comment


                      • #12
                        Success! mostly..

                        Woop!

                        So, I managed to get my Injection adapter working a little while ago.. for the most part.

                        useValue is sorted out (extending DefaultListableObjectFactory and throwing the value/instance in the singletonCache worked perfectly), but now I'm having trouble with the singletons: dependencies aren't being injected on lazily instantiated singletons.

                        In essence I think it comes down to this: things work out when I instantiate objects and then inject into them manually (using injectInto), but objects that get constructed by the Spring container, don't end up having their dependencies resolved - Spring obviously ignores my [Inject] annotations.

                        I tried to work around this by inspecting class metadata for dependencies when I set up injection rules through my adapter. But how Spring is supposed to figure out my named injection points I'm not sure

                        Here's how it's looking:

                        Code:
                        package net.boyblack.robotlegs.adapters
                        {
                            import net.boyblack.robotlegs.core.IInjector;
                        
                            import org.as3commons.lang.ClassUtils;
                            import org.as3commons.lang.ObjectUtils;
                            import org.as3commons.reflect.Field;
                            import org.as3commons.reflect.MetaData;
                            import org.as3commons.reflect.Type;
                            import org.springextensions.actionscript.ioc.ObjectDefinition;
                            import org.springextensions.actionscript.ioc.ObjectDefinitionScope;
                            import org.springextensions.actionscript.ioc.factory.support.RobotLegsObjectFactory;
                        
                            public class SpringInjector implements IInjector
                            {
                                protected var factory:RobotLegsObjectFactory;
                        
                                public function SpringInjector()
                                {
                                    factory = new RobotLegsObjectFactory();
                                }
                        
                                public function bindValue(whenAskedFor:Class, useValue:Object, named:String = null):void
                                {
                                    var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                    var useClassName:String = ObjectUtils.getFullyQualifiedClassName(useValue);
                                    var key:String = named ? named : whenAskedForClassName;
                                    registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.SINGLETON);
                                    factory.cacheSingletonValue(key, useValue);
                                }
                        
                                public function bindClass(whenAskedFor:Class, instantiateClass:Class, named:String = null):void
                                {
                                    var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                    var useClassName:String = ClassUtils.getFullyQualifiedName(instantiateClass);
                                    var dependencies:Array = findDependencies(instantiateClass);
                                    registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.PROTOTYPE, dependencies);
                                }
                        
                                public function bindSingleton(whenAskedFor:Class, named:String = null):void
                                {
                                    var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                    var useClassName:String = whenAskedForClassName;
                                    var dependencies:Array = findDependencies(whenAskedFor);
                                    registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.SINGLETON, dependencies);
                                }
                        
                                public function bindSingletonOf(whenAskedFor:Class, useSingletonOf:Class, named:String = null):void
                                {
                                    var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                    var useClassName:String = ClassUtils.getFullyQualifiedName(useSingletonOf);
                                    var dependencies:Array = findDependencies(useSingletonOf);
                                    registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.SINGLETON, dependencies);
                                }
                        
                                public function injectInto(target:Object):void
                                {
                                    var type:Type = Type.forInstance(target);
                                    var fields:Array = type.fields;
                                    for each (var field:Field in fields)
                                    {
                                        if (field.hasMetaData('Inject'))
                                        {
                                            var named:String = null;
                                            var mds:Array = field.getMetaData('Inject');
                                            for each (var md:MetaData in mds)
                                            {
                                                if (md.hasArgumentWithKey('name'))
                                                {
                                                    named = md.getArgument('name').value;
                                                    break;
                                                }
                                                else if (md.hasArgumentWithKey('id'))
                                                {
                                                    named = md.getArgument('id').value;
                                                    break;
                                                }
                                            }
                                            named = named ? named : field.type.fullName;
                                            target[field.name] = factory.getObject(named);
                                        }
                                    }
                                }
                        
                                public function unbind(clazz:Class, named:String = null):void
                                {
                                    named = named ? named : ClassUtils.getFullyQualifiedName(clazz);
                                    factory.removeObjectDefinition(named);
                                }
                        
                                protected function registerObjectDefinition(whenAskedForClassName:String, useClassName:String, named:String, scope:ObjectDefinitionScope, dependencies:Array = null):void
                                {
                                    var objdef:ObjectDefinition = new ObjectDefinition(useClassName);
                                    var key:String = named ? named : whenAskedForClassName;
                                    objdef.dependsOn = dependencies ? dependencies : objdef.dependsOn;
                                    objdef.scope = scope;
                                    factory.registerObjectDefinition(key, objdef);
                                }
                        
                                protected function findDependencies(clazz:Class):Array
                                {
                                    var type:Type = Type.forClass(clazz);
                                    var fields:Array = type.fields;
                                    var dependencies:Array = new Array();
                                    for each (var field:Field in fields)
                                    {
                                        if (field.hasMetaData('Inject'))
                                        {
                                            var named:String = null;
                                            var mds:Array = field.getMetaData('Inject');
                                            for each (var md:MetaData in mds)
                                            {
                                                if (md.hasArgumentWithKey('name'))
                                                {
                                                    named = md.getArgument('name').value;
                                                    break;
                                                }
                                                else if (md.hasArgumentWithKey('id'))
                                                {
                                                    named = md.getArgument('id').value;
                                                    break;
                                                }
                                            }
                                            named = named ? named : field.type.fullName;
                                            dependencies.push(named);
                                        }
                                    }
                                    trace('dependencies for ' + clazz + ' : ' + dependencies);
                                    return dependencies;
                                }
                        
                            }
                        }

                        Comment


                        • #13
                          IOBjectDefinition

                          You will have to construct those dependencies yourself and add them to the objectdefinition.
                          So, take a good look at the ObjectDefinition sources, all dependency and injection information can be stored in there.
                          One thing you have remember, if you are injecting another object (one that is managed by your container) into a property or whatever, add this to the ObjectDefinition as a RuntimeObjectReference. This is an implementation of the IObjectReference interface, which only needs to have one property: objectName.
                          This objectName is the name with which an object is registered in the container, by adding using this RuntimeObjectReference in your ObjectDefinitions the container will understand that it needs to retrieve the object from itself, through the usual getObject() pipeline.

                          I created a graphical view of the getObject flow in the reference docs:

                          http://www.springactionscript.org/docs/reference/html/container-documentation.html#a_graphical_overview_of_the_get object_flow


                          I hope this helps, good luck to you,


                          Roland
                          Last edited by 666shooter; Jul 16th, 2009, 03:15 AM. Reason: added API reference links

                          Comment


                          • #14
                            RuntimeObjectReference

                            Thank you Roland, you rock! All I needed to do was set some RuntimeObjectReferences on the properties object of the ObjectDefinition.

                            For anyone who's interested, here's how to use Spring "Guice/SmartyPants style" (I'm sure it can be improved though):

                            Code:
                            package net.boyblack.robotlegs.adapters
                            {
                                import net.boyblack.robotlegs.core.IInjector;
                                
                                import org.as3commons.lang.ClassUtils;
                                import org.as3commons.lang.ObjectUtils;
                                import org.as3commons.reflect.Field;
                                import org.as3commons.reflect.MetaData;
                                import org.as3commons.reflect.Type;
                                import org.springextensions.actionscript.ioc.ObjectDefinition;
                                import org.springextensions.actionscript.ioc.ObjectDefinitionScope;
                                import org.springextensions.actionscript.ioc.factory.config.RuntimeObjectReference;
                                import org.springextensions.actionscript.ioc.factory.support.RobotLegsObjectFactory;
                            
                                public class SpringInjector implements IInjector
                                {
                                    protected var factory:RobotLegsObjectFactory;
                            
                                    public function SpringInjector()
                                    {
                                        factory = new RobotLegsObjectFactory();
                                    }
                            
                                    public function bindValue(whenAskedFor:Class, useValue:Object, named:String = null):void
                                    {
                                        var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                        var useClassName:String = ObjectUtils.getFullyQualifiedClassName(useValue);
                                        var key:String = named ? named : whenAskedForClassName;
                                        registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.SINGLETON);
                                        factory.cacheSingletonValue(key, useValue);
                                    }
                            
                                    public function bindClass(whenAskedFor:Class, instantiateClass:Class, named:String = null):void
                                    {
                                        var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                        var useClassName:String = ClassUtils.getFullyQualifiedName(instantiateClass);
                                        var properties:Object = findProperties(instantiateClass);
                                        registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.PROTOTYPE, properties);
                                    }
                            
                                    public function bindSingleton(whenAskedFor:Class, named:String = null):void
                                    {
                                        var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                        var useClassName:String = whenAskedForClassName;
                                        var properties:Object = findProperties(whenAskedFor);
                                        registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.SINGLETON, properties);
                                    }
                            
                                    public function bindSingletonOf(whenAskedFor:Class, useSingletonOf:Class, named:String = null):void
                                    {
                                        var whenAskedForClassName:String = ClassUtils.getFullyQualifiedName(whenAskedFor);
                                        var useClassName:String = ClassUtils.getFullyQualifiedName(useSingletonOf);
                                        var properties:Object = findProperties(useSingletonOf);
                                        registerObjectDefinition(whenAskedForClassName, useClassName, named, ObjectDefinitionScope.SINGLETON, properties);
                                    }
                            
                                    public function injectInto(target:Object):void
                                    {
                                        var type:Type = Type.forInstance(target);
                                        var fields:Array = type.fields;
                                        for each (var field:Field in fields)
                                        {
                                            if (field.hasMetaData('Inject'))
                                            {
                                                var named:String = null;
                                                var mds:Array = field.getMetaData('Inject');
                                                for each (var md:MetaData in mds)
                                                {
                                                    if (md.hasArgumentWithKey('name'))
                                                    {
                                                        named = md.getArgument('name').value;
                                                        break;
                                                    }
                                                    else if (md.hasArgumentWithKey('id'))
                                                    {
                                                        named = md.getArgument('id').value;
                                                        break;
                                                    }
                                                }
                                                named = named ? named : field.type.fullName;
                                                target[field.name] = factory.getObject(named);
                                            }
                                        }
                                    }
                            
                                    public function unbind(clazz:Class, named:String = null):void
                                    {
                                        named = named ? named : ClassUtils.getFullyQualifiedName(clazz);
                                        factory.removeObjectDefinition(named);
                                    }
                            
                                    protected function registerObjectDefinition(whenAskedForClassName:String, useClassName:String, named:String, scope:ObjectDefinitionScope, properties:Object = null):void
                                    {
                                        var objdef:ObjectDefinition = new ObjectDefinition(useClassName);
                                        var key:String = named ? named : whenAskedForClassName;
                                        objdef.properties = properties ? properties : objdef.properties;
                                        objdef.scope = scope;
                                        factory.registerObjectDefinition(key, objdef);
                                    }
                            
                                    protected function findProperties(clazz:Class):Object
                                    {
                                        var type:Type = Type.forClass(clazz);
                                        var fields:Array = type.fields;
                                        var properties:Object = new Object();
                                        for each (var field:Field in fields)
                                        {
                                            if (field.hasMetaData('Inject'))
                                            {
                                                var named:String = null;
                                                var mds:Array = field.getMetaData('Inject');
                                                for each (var md:MetaData in mds)
                                                {
                                                    if (md.hasArgumentWithKey('name'))
                                                    {
                                                        named = md.getArgument('name').value;
                                                        break;
                                                    }
                                                    else if (md.hasArgumentWithKey('id'))
                                                    {
                                                        named = md.getArgument('id').value;
                                                        break;
                                                    }
                                                }
                                                named = named ? named : field.type.fullName;
                                                properties[field.name] = new RuntimeObjectReference(named);
                                            }
                                        }
                                        return properties;
                                    }
                            
                                }
                            }
                            And the Object Factory:

                            Code:
                            package org.springextensions.actionscript.ioc.factory.support
                            {
                                import org.springextensions.actionscript.ioc.IObjectDefinition;
                            
                                public class RobotLegsObjectFactory extends DefaultListableObjectFactory
                                {
                                    public function RobotLegsObjectFactory()
                                    {
                                        super();
                                    }
                            
                                    public function cacheSingletonValue(objectName:String, value:Object):void
                                    {
                                        singletonCache[objectName] = value;
                                    }
                            
                                }
                            }
                            Last edited by drscn; Jul 16th, 2009, 07:59 AM. Reason: To add Object Factory definition

                            Comment


                            • #15
                              congrats!

                              Hey Shaun,

                              I'm happy to see you got everything working fairly quickly, cheers on that!

                              I already had a feeling you were the Shaun from 'RobotLegs' fame Really nice to see this type of integration, thanks!

                              greets,

                              Roland

                              Comment

                              Working...
                              X