The necessary conditions of injection to work

naghekyan's Avatar

naghekyan

17 Nov, 2013 07:05 PM

I use RL2 and want to inject a value in an arbitrary class (that class in not View, Mediator, Model or Service), it is just a class in my app. What should I do?

I have written the following:

var inst : IMyClass = new MyClass;
injector.map(IMyClass ).toValue(inst);

And in MyClassB I write:

[Inject]
public var _myClass : IMyClass;

Is this enough for injection?

  1. 1 Posted by matej on 18 Nov, 2013 08:46 AM

    matej's Avatar

    Yes if you create MyClassB with injector.

    so, instead of just doing new MyClassB() you would:

    1. injector.map(MyClassB)
    and then in some other class

    [Inject]
    public var myClassB:MyClassB;

    or you could
    [Inject]
    public var injector:IInjector;

    and then
    injector.instantiateUnmapped(MyClassB);

    then, injector will provide MyClassB with all dependencies.

    Note that you can use

    injector.map(IMyClass).toSignleton(MyClass);

    to achieve the same thing you did for IMyClass mapping;

  2. 2 Posted by naghekyan on 18 Nov, 2013 10:41 AM

    naghekyan's Avatar

    Why I need to use `instantiateUnmapped`.Why I cannot instantiate as I have wrote in my question? The rule of mapping is defined below, isn't it?

    var inst : IMyClass = new MyClass;
    injector.map(IMyClass ).toValue(inst);

  3. 3 Posted by matej on 18 Nov, 2013 12:53 PM

    matej's Avatar

    Yes,

    that is another option.

    You just want the injector to create it.

  4. 4 Posted by naghekyan on 18 Nov, 2013 01:39 PM

    naghekyan's Avatar

    It this case why when I inject, then the injected value is null?

  5. 5 Posted by matej on 18 Nov, 2013 02:40 PM

    matej's Avatar

    Lets start from zero :)

    to use [Inject] in any class, that class has to be created with injector.

    there are multiple ways to create the class with injector, but plain new Class() will not work.

    1. you can create the class most directly with injector.instantiateUnmapped.
    2. You can map the class with injector.map(Class) in your config, and then inject the class into some other class, command model ext…

    [Inject]
    public var classWithInjections:Class();

    Where does it come null to you?

  6. Support Staff 6 Posted by Ondina D.F. on 18 Nov, 2013 05:16 PM

    Ondina D.F.'s Avatar

    I wrote down a pretty long explanation, but then I had to do something else and couldn't continue. Even though Matey has already answered your questions, I'll post my unfinished answer too, just to confuse you some more :P

    It this case why when I inject, then the injected value is null?

    There could be lots of causes for that. Without more info it is impossible to know what's going on in your app.

    Some of the common causes are here : https://github.com/robotlegs/robotlegs-framework/wiki/Common-Problems

    Where are you trying to inject IMyClass? Does the class that needs IMyClass have a mapping, i.e. does the Injector know about it?

    Let's say you want to inject ClassC into ClassB, and ClassB into ClassA.

    You need a mapping for all of them, and as Matej already told you, the injector has to be the one who instantiates them, in a way or another.

    injector.map(ClassA).asSingleton();
    injector.map(ClassB).asSingleton();
    injector.map(ClassC).asSingleton();
    

    Now, the Injector has rules for the 3 classes. But, the mapping alone isn't enough to make the injection happen. The Injector needs an injection point:

    ** ClassA **

    [Inject]
    public var classB:ClassB;
    

    First now it will instantiate ClassB. The Injector instantiates classes only on request. The injection point, in the above case, represents the request. It says, dear Injector, I really need ClassB to be injected in here. The Injector looks for an existing mapping for ClassB, and if it finds one, it provides the needy class with an instance of ClassB (same or new, depending on the mapping). So, both, ClassA and ClassB must have a mapping.

    Variant 1a + error:

    injector.map(ClassA).asSingleton();  
            
    var classB:ClassB = injector.getOrCreateNewInstance(ClassB);
    //or
    //var classB:ClassB = injector. instantiateUnmapped (ClassB);
    
    injector.map(ClassB).toValue(classB);
                
    injector.map(ClassC).asSingleton();
    

    You'd get an error for a missing rule for ClassC, because ClassB has been instantiated before its dependency (ClassC) could be provided.
    The [Inject] public var classC:ClassC; inside ClassB is a request to instantiate ClassC, but without a mapping the Injector will reject the request (Injector is missing a mapping to handle injection into property....)

    So, you'd have to change the order of the mappings.

    Variant 1b + no error:

    injector.map(ClassA).asSingleton();//1
        
    injector.map(ClassC).asSingleton();//2
            
    var classB:ClassB = injector.getOrCreateNewInstance(ClassB);//3
    injector.map(ClassB).toValue(classB);
    

    Variant 2a + error:

    injector.map(ClassA).asSingleton();
    
    var classB:ClassB = new ClassB();           
    injector.map(ClassB).toValue(classB);
    
    injector.map(ClassC).asSingleton();
    

    Here, the injection of ClassB into ClassA will work, but ClassC won't be injected into ClassC. ClassB has a mapping, but the Injector can't fulfil the request for ClassC.

    Variant 2b + no error:

    injector.map(ClassA).asSingleton();
    
    injector.map(ClassC).asSingleton();
    
    var classB:ClassB = new ClassB();
    injector.map(ClassB).toValue(classB);
    
    injector.injectInto(classB);//the object, not the Class!
    

    injectInto() Inspects the given object and injects into all injection points configured for its class. The Injector must have mappings for all injection points.

    Look at the comments inside Injector and InjectionMapping:
    https://github.com/robotlegs/swiftsuspenders/blob/master/src/org/sw...

    https://github.com/robotlegs/swiftsuspenders/blob/master/src/org/sw...

    Here the 3 Classes. You can play around with different mappings. Somewhere, where you inject ClassA, put a trace for classA.aProperty.

     public class ClassA
        {
            [Inject]
            public var classB:ClassB;
    
            private var _aProperty:String = "aaa";
    
            public function ClassA()
            {
                trace("ClassA.ClassA()");
            }
    
            public function get aProperty():String
            {
                return _aProperty + " " + classB.bProperty;
            }
    
            public function set aProperty(value:String):void
            {
                _aProperty = value;
            }
    
        }
        public class ClassB
        {
            [Inject]
            public var classC:ClassC;
    
            private var _bProperty:String = "bbb";
    
            public function ClassB()
            {
                trace("ClassB.ClassB()");
    
                //BAD: classC is not available in the constructor
                //trace("ClassB.ClassB() "+classC.cProperty);
            }
    
            public function get bProperty():String
            {
                trace("ClassB.bProperty()");
    
                return _bProperty + " " + classC.cProperty;
            }
    
            public function set bProperty(value:String):void
            {
                _bProperty = value;
            }
    
        }
        public class ClassC
        {
            private var _cProperty:String = "ccc";
    
            public function ClassC()
            {
                trace("ClassC.ClassC()");
            }
    
            public function get cProperty():String
            {
                return _cProperty;
            }
    
            public function set cProperty(value:String):void
            {
                _cProperty = value;
            }
    
        }
    
  7. 7 Posted by naghekyan on 19 Nov, 2013 10:29 AM

    naghekyan's Avatar

    @matej, @Ondina guys! I am so impressed with great the help you provide. This was so complete and descriptive. Thank you for your time and effort guys!

  8. Support Staff 8 Posted by Ondina D.F. on 19 Nov, 2013 11:15 AM

    Ondina D.F.'s Avatar

    Thanks for the kind words! We, guys and girls, men and women, in the robotlegs community are glad to be of help ;)

    May I mark this discussion as resolved?

  9. 9 Posted by naghekyan on 19 Nov, 2013 03:28 PM

    naghekyan's Avatar

    Sure! :)

  10. Ondina D.F. closed this discussion on 19 Nov, 2013 05:02 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac