Misunderstanding the [PostConstruct] metatag

poq2011's Avatar

poq2011

02 Mar, 2013 02:50 PM

Hi all,

I have what seems to be a common problem for RL beginners : Injected Property which in Null In a custom class

I've read several post about it + the common problems on the wiki, but i could not figure out what i am missing.

In my context Class, I have (I am using the Robotlegs Away3D 4 integration by Paul Tondeur )

     override protected function mapInjections() : void {
            trace('myContext3D :: mapInjections');
            super.mapInjections();
            injector.mapValue(myAway3DView, view3D);

        }       
        
        override public function get view3D():View3D{
            return (_myAway3DView || (_myAway3DView = new myAway3DView(_showGrid, _showTrident, _showAxis, _backgroundColor)));
        }

Now I want to inject 'myAway3DView into a Custom Class. I use the [PostConstruct] metatag : I 've written the following :

public class myCustomClass{

        [Inject]
        public var away3DView : myAway3DView;

        public function myCustomClass()
        {
            trace('myCustomClass:: ');
            init();         
        }

[PostConstruct]
        public function init():void{
            trace('my3DObjectBase :: init',away3DView  );
        }
}

but doing this leads to away3DView to be null

What am i missing??

  1. Support Staff 1 Posted by Stray on 02 Mar, 2013 03:37 PM

    Stray's Avatar

    Take the init() out of the constructor (the myCustomClass function) - this is causing it to run early. The [PostConstruct] tag will ensure that the init() function is run once injections are complete.

    hth,

    Stray

  2. 2 Posted by poq2011 on 03 Mar, 2013 11:57 AM

    poq2011's Avatar

    Thanks for helping

    If i take the init() function out of the constructor, init() is never fired

  3. Support Staff 3 Posted by Shaun Smith on 03 Mar, 2013 10:09 PM

    Shaun Smith's Avatar

    Hi poq2011,

    If init() is not fired then your instance is not being constructed by the Injector. How are you instantiating myCustomClass?

    BTW, it is very unusual (and a bit confusing) to have classes that start with lowercase characters in AS3. myCustomClass should really be MyCustomClass. Instances on the other hand should always start with lowercase characters. For example:

    var thing:Thing = new Thing();
    

    Anyhoo, for [Inject] or [PostConstruct] to work the instance needs to be constructed by the Injector. If you are new'ing it up yourself the Injector won't know anything about it and thus won't be able to resolve any dependencies or call the [PostContruct] method for you.

    The Injector is a Factory. You give it a some configuration information, and then you ask it to build objects for you. It analyses the metadata in the class you are wanting to instantiate and resolves dependencies recursively using the information you've given it. But it's still just a Factory, it doesn't know anything about objects that you haven't told it about or objects that it didn't built itself.

    Most of the things in the framework, like Mediators and Commands, are constructed using the Injector, and that is why they can have [Inject] and [PostConstruct] metadata tags.

    So, if you tell the injector how to construct 'MyCustomClass` and then inject that into something that is created by the injector (like a Command) you should see things working correctly:

    // in your mapInjections() method
    injector.mapSingleton(MyCustomClass);
    
    // in a command or mediator
    [Inject]
    public var myCustomClass:MyCustomClass;
    

    Here we've told the injector what to do when someone needs an instance of MyCustomClass. An instance of this class won't be created until someone needs it. Because the Command/Mediator needs it, and because that Command/Mediator is created by the Injector, the Injector can create it, resolve it, and inject it successfully.

    Hope that clears things up a bit.

  4. 4 Posted by poq2011 on 04 Mar, 2013 08:04 AM

    poq2011's Avatar

    thanks that clarify the Injection mechanism.

    However, if I understand well, I shouldn't need the [PostContruct] metatag.

    I want to inject away3DView : MyAway3DView; into a custom class MyCustomClass.

    So in my context class, I've configured the injector by declaring

    injector.mapValue(myAway3DView, view3D);

    By doing so i should be able a get the instance of my class MyAway3DView in any custom class constructed manually, no?

    public class MyCustomClass{

        [Inject]
        public var away3DView : MyAway3DView;
    

    }

    but away3DView is always null. What's wrong?

  5. Support Staff 5 Posted by Shaun Smith on 04 Mar, 2013 10:20 AM

    Shaun Smith's Avatar

    Hello,

    By "always null" do you mean: null in the constructor?

    A public property can not be set on an instance before that instance has been constructed. This is what [PostConstruct] is for. The instance needs to be constructed first, and then any properties can be set, and then you need a way to know that all the properties have been set. Please see:

    https://github.com/robotlegs/robotlegs-framework/wiki/Common-Problems#wiki-null-in-constructor

    Hope that helps

  6. 6 Posted by poq2011 on 04 Mar, 2013 10:04 PM

    poq2011's Avatar

    Thanks but that didn't help.

    Here is attached an example of what I'm trying to do. In short :

    my AppContext maps an instance of MyClassToBeInjected with injector.mapValue(MyClassToBeInjected, myClassToBeInjectedInstance). This instance is added to contextView.

    I have a ADummyView mapped to ADummyViewMediator. This component listens to stage Mouse Click

    I have a MyServiceConstructingMyCustomClass service which is in charge of constructing an instance of MyCustomClass.

    The command ConstructMyCustomClassCommand is mapped to the event MyAppEvent.CONSTRUCT_CLASS which is dispatched by ADummyViewMediator when a click on stage occurs. I want to get the injection of the instance of MyClassToBeInjected in 'MyCustomClass()` when I instanciate this class.

    How to achieve that? In my code, in MyCustomClass() the injection of myClassToBeInjectedInstance is always null and the postConstruct method is never fired even if an injection rule (in this case injector.mapSingleton(MyCustomClass) in the context ) is declared for this class.

  7. Support Staff 7 Posted by Shaun Smith on 04 Mar, 2013 10:12 PM

    Shaun Smith's Avatar

    Hi. Could you post that as a ZIP? I don't have any tools for unpacking RAR files.

  8. Support Staff 8 Posted by Shaun Smith on 04 Mar, 2013 10:21 PM

    Shaun Smith's Avatar

    I have a MyServiceConstructingMyCustomClass service which is in charge of constructing an instance of MyCustomClass.

    If you are constructing the MyCustomClass instances yourself then the Injector won't know about them. You need to use the injector to create the instances. You can do this like so: injector.getInstance(MyCustomClass).

  9. Support Staff 9 Posted by Shaun Smith on 04 Mar, 2013 10:23 PM

    Shaun Smith's Avatar

    BTW, do you need to use a service to manually create these instance? Have you tried simply injecting MyCustomClass into your mediator and seeing what happens?

  10. 10 Posted by poq2011 on 05 Mar, 2013 06:38 AM

    poq2011's Avatar

    Here is the zip file.

    If you are constructing the MyCustomClass instances yourself then the Injector won't know about them. You need to use the injector to create the instances. You can do this like so: injector.getInstance(MyCustomClass).

    I want to inject 'myClassToBeInjectedInstance' when creating 'MyCustomClass', so it should be 'injector.getInstance(myClassToBeInjectedInstance)'
    How do i get access to the property 'injector'?

    Have you tried simply injecting MyCustomClass into your mediator and seeing what happens?

    You mean tried to inject 'myClassToBeInjectedInstance' into the meditaor. Yes I did, and it works as expected, null in the constructor, but 'postConstruct' and 'onRegister' methods have access to the injection.

    BTW, do you need to use a service to manually create these instance?

    Yes Ithink so. I need to create manually objects depending on data I've previously loaded on my Model and in response to a specific event. What would you suggest?

  11. Support Staff 11 Posted by Shaun Smith on 05 Mar, 2013 09:43 AM

    Shaun Smith's Avatar

    Hi. You can inject it into your service:

    [Inject] public var injector:IInjector;

  12. 12 Posted by poq2011 on 05 Mar, 2013 10:38 AM

    poq2011's Avatar

    Hi,

    OK but I'd rather need the injector in MyCustomClass in order to access myClassToBeInjectedInstance via injector.getInstance(myClassToBeInjected).

    Am I not going to run in the same problem since I still need to do an injection, this time the injector itself??

  13. Support Staff 13 Posted by Shaun Smith on 05 Mar, 2013 02:28 PM

    Shaun Smith's Avatar

    No, that's not what I mean. Inject the injector into your service, and use it to create the MyCustomClass instances

  14. 14 Posted by poq2011 on 05 Mar, 2013 07:53 PM

    poq2011's Avatar

    Thanks for helping!

    Ok, it seems to work, but I don't understand why!

    In my service, what the difference between this line of code

    var temp : MyCustomClass = injector.getInstance(MyCustomClass); which will resolve all injections in MyCustomClass

    and this line

    var temp : MyCustomClass =new MyCustomClass;

    which won'tresolve the injections in MyCustomClass ?

    It seems quite magical to me...

  15. Support Staff 15 Posted by Shaun Smith on 06 Mar, 2013 11:22 PM

    Shaun Smith's Avatar

    Hehe, it is the opposite of magical!

    If this worked, it would be magical indeed:

    var temp : MyCustomClass = new MyCustomClass();
    

    In that case there is no system to analyse the Class metadata and perform any processing.

  16. Support Staff 16 Posted by Ondina D.F. on 25 Mar, 2013 11:21 AM

    Ondina D.F.'s Avatar

    I guess this is resolved, right? I’m closing this discussion for now. You can re-open it, if need be.

  17. Ondina D.F. closed this discussion on 25 Mar, 2013 11:21 AM.

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