SwiftSuspenders injection mappings not working

sascha's Avatar

sascha

30 Apr, 2011 06:03 AM

This is a question completely unrelated to RL but only related to SwiftSuspenders as I'm trying to use these in my own code base, but I can't find any support forum for SwiftSuspenders so I'm trying my luck here...

I've did basically everything like it's set up in RL but after mapping injections with SwiftSuspenders the injected references are still null. For example I use

injector.mapValue(EntityManager, entityManager);

and in another class (instanceThatNeedsEntityManagerRef) I inject entityManager like this:

[Inject] public var entityManager:EntityManager;

but when accessing entityManager it remains null. The only way I get it to work is to use injectInto(instanceThatNeedsEntityManagerRef) but that's pointless since the class doing injections shouldn't need to know instanceThatNeedsEntityManagerRef. What am I missing here? Checking the RL Context classes I don't see any injectInto() being used but it works there.

Of course keep-as3-metadata += Inject, PostConstruct is used so that shouldn't be the problem.

  1. Support Staff 1 Posted by Stray on 30 Apr, 2011 08:17 AM

    Stray's Avatar

    Hi Sascha,

    no worries - this is probably the best place to ask SS questions too - Till has been on holiday but he should be back soon, and the rest of us have a pretty good (but not as amazing as Till's) understanding of the workings of SS.

    So - I have a question:

    How is the class (instanceThatNeedsEntityManagerRef) being instantiated?

    Robotlegs uses the injector to instantiate any Command, Actor, Mediator etc that you use, and these are generally where injections are happening. These classes usually contain your other classes-with-injections and so these are in turn created by the SS injector.

    If you just do new ThingThatNeedsInjections() in Robotlegs you'd find you needed to do injector.injectInto() afterwards to fulfil the injections too.

    Think of the SS injector like a factory with 2 main working approaches - you can ask it to make an object for you from scratch, or you can ask it to process an object you already made.

    Auto DI isn't magic - you always have to directly invite the factory to create or process your object in order to get those injections it needs fulfilled.

    If you want to paste specific code samples feel free, and we'll take a closer look.

    I hope that helps get you on the right track - if you were already instantiating your objects through the SS factory then it'll be something else and we can look for that with you too,

    Stray

  2. 2 Posted by sascha on 30 Apr, 2011 09:32 AM

    sascha's Avatar

    Thanks for the explanation Stray! I thought that there was indeed some reflection-kind-of stuff going on under the hood of SS to fetch injection points but now the whole architecture seems a lot clearer.

    There are quite a few classes in my project that are instantiated in various places, e.g. screen objects that are created in a ScreenManager class that need injections etc.
    The base injections happen in a class called Main but Main doesn't have references to classes like the ScreenManager and definitely not to the screen classes.

    I guess since Main acts as a sort of Singleton I could make the injector in Main accessible to other classes which could then use it to use injectInto() but that feels a bit awkward to me and is probably not in the sense of SS/DI.

    Have to wrap my head around this issue a little more!

  3. Support Staff 3 Posted by Stray on 02 May, 2011 12:07 PM

    Stray's Avatar

    No problem - good luck figuring it out - the whole process of achieving good cooperation / communication without making the code very tightly bound or hard to test (due to statics) is quite complex.

    Is there a reason why you're wanting to use SS outside of Robotlegs? If it's just a case of wanting different behaviour to the standard robotlegs MVCS 'trousers' then maybe you'd be better to create a new set of 'trousers' but still use the Robotlegs core?

    Stray

  4. 4 Posted by sascha on 02 May, 2011 12:23 PM

    sascha's Avatar

    Stray, the project I'm working on is a game engine and I found that RL would add too much overhead to a project like that where performance is often very critical. That's why I prefer to cook my own stuff here. RL might be great especially for MVC applications but in this case (an entity component based approach) it's just too much on top that get's in the way for me.

  5. Support Staff 5 Posted by Stray on 02 May, 2011 12:51 PM

    Stray's Avatar

    I thought that was probably the case. I'd recommend that you have a chat with Mike Cann (he's on here and is also @mikeysee on Twitter - he did something similar a little over a year ago - specifically an entity component based approach, so I'm sure you can benefit a ton from what he learned.

    My own opinion is that if performance is critical you can't use reflection-based DI. You're giving away so much in the reflection process that it's very hard to justify IMO. The balance is really dictated by the number of different classes being reflected - caching can help if you've got a limited range.

    Stray

  6. 6 Posted by sascha on 02 May, 2011 01:06 PM

    sascha's Avatar

    Thanks, I gotta have a look out for Mike! :)

    I've read about that reflection-based DI isn't the best bet when performance for game development is important, especially in Flash. Let's just say I want to get my feet wet a little with DI and see how it goes. If it becomes a performance problem I can still transform the DI code rather easily. On the other hand converting the whole project to adapt to a RL setup I think would be much more of a venture to reverse back from., that why I only used SS for now.

  7. Support Staff 7 Posted by Stray on 02 May, 2011 01:10 PM

    Stray's Avatar

    Definitely - and that's a good way to think of it.

    So - in this case I would do what Robotlegs does with IInjector and use an interface on the DI factory to decouple it completely from the code that uses it, so that you can use a different solution very easily in future. I'm sure you were planning on doing that anyway.

    I wasn't suggesting pulling robotlegs in by the way - I was just thinking that some of the patterns / solutions in the viewMap and so on might be relevant to you as a starting point. Robotlegs itself isn't the Actor / Mediator / Context / Command stuff that is in the MVCS package - it's the layer underneath (which always confuses people!)

    Stray

  8. 8 Posted by patricklemiuex on 08 May, 2011 01:19 PM

    patricklemiuex's Avatar

    I'm having issues with swift-suspenders and robot legs in hero, injections simply aren't working correctly with Hero. I've tried 1.51 suspenders and 1.6. I get different types of errors - but here's a suspect error:

    So my model isn't being injected for some reason? I'm kind of stuck on this. If I switch to 1.6 os swift suspenders i get a bunch of warnings about things mapping again and again. any suggestions here?

    Error: Injector is missing a rule to handle injection into target [object UserProxy]. Target dependency: net.voxel.business::ServiceDelegate

    at org.swiftsuspenders.injectionpoints::PropertyInjectionPoint/applyInjection()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionpoints/PropertyInjectionPoint.as:42]
    at org.swiftsuspenders::Injector/injectInto()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:120]
    at org.swiftsuspenders::Injector/instantiate()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:134]
    at org.swiftsuspenders.injectionresults::InjectSingletonResult/createResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionresults/InjectSingletonResult.as:40]
    at org.swiftsuspenders.injectionresults::InjectSingletonResult/getResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionresults/InjectSingletonResult.as:31]
    at org.swiftsuspenders::InjectionConfig/getResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/InjectionConfig.as:41]
    at org.swiftsuspenders::InjectionConfig/getResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/InjectionConfig.as:47]
    at org.swiftsuspenders.injectionpoints::PropertyInjectionPoint/applyInjection()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionpoints/PropertyInjectionPoint.as:36]
    at org.swiftsuspenders::Injector/injectInto()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:120]
    at org.swiftsuspenders::Injector/instantiate()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:134]
    at org.robotlegs.base::CommandMap/execute()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/CommandMap.as:168]
    at org.robotlegs.base::CommandMap/routeEventToCommand()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/CommandMap.as:223]
    at Function/<anonymous>()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/CommandMap.as:98]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at org.robotlegs.mvcs::Mediator/dispatch()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/mvcs/Mediator.as:89]
    at net.voxel.voxcloud.view.mediator::LoginMediator/onLogin()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/net/voxel/voxcloud/view/mediator/LoginMediator.as:32]
    at org.robotlegs.base::EventMap/routeEventToListener()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/EventMap.as:181]
    at Function/<anonymous>()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/EventMap.as:107]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at mx.core::UIComponent/dispatchEvent()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:13125]
    at net.voxel.voxcloud.view::LoginView/login()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/net/voxel/voxcloud/view/LoginView.mxml:32]
    at net.voxel.voxcloud.view::LoginView/___LoginView_Button1_click()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/net/voxel/voxcloud/view/LoginView.mxml:74]
    
  9. 9 Posted by Stray on 08 May, 2011 01:42 PM

    Stray's Avatar

    Hi Patrick - SS 1.6 Warnings about re-mapping when using Flex are not as serious as they look, I'm currently working on a patch for that. The root cause is that because the contextView has to be set as a property in flex (rather than passed in as a constructor arg) the context re-starts when it has a new contextView set.

    Basically the exact same thing is happening as in 1.5 (or before) - but starting with 1.6, SS reports those re-mappings, so we've realised that it's not ideal and are looking at a non-breaking change in that start-up flow in flex.

    So - definitely go for 1.6 SS.

    Then let me know if you get errors still - and if you want to paste your code for where you're mapping the UserProxy, that would be great.

    Thanks,

    Stray

  10. 10 Posted by patricklemiuex on 08 May, 2011 05:08 PM

    patricklemiuex's Avatar

    Yeah, the user proxy:

    https://github.com/reduxdj/VoxCLOUD/blob/master/src/net/voxel/voxcloud/ApplicationContext.as

    I downgraded 1.51. Still curious why the proxy is null, is there
    something I misunderstand about how to use robot legs?
    Or do you think it might be related to component lifecycle of hero? Curious.

     Injector is missing a rule to handle injection into target [object
    UserProxy]. Target dependency: net.voxel.business::ServiceDelegate
    at org.swiftsuspenders.injectionpoints::PropertyInjectionPoint/applyInjection()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionpoints/PropertyInjectionPoint.as:42]
    at org.swiftsuspenders::Injector/injectInto()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:120]
    at org.swiftsuspenders::Injector/instantiate()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:134]
    at org.swiftsuspenders.injectionresults::InjectSingletonResult/createResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionresults/InjectSingletonResult.as:40]
    at org.swiftsuspenders.injectionresults::InjectSingletonResult/getResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionresults/InjectSingletonResult.as:31]
    at org.swiftsuspenders::InjectionConfig/getResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/InjectionConfig.as:41]
    at org.swiftsuspenders::InjectionConfig/getResponse()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/InjectionConfig.as:47]
    at org.swiftsuspenders.injectionpoints::PropertyInjectionPoint/applyInjection()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/injectionpoints/PropertyInjectionPoint.as:36]
    at org.swiftsuspenders::Injector/injectInto()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:120]
    at org.swiftsuspenders::Injector/instantiate()[/Users/tschneidereit/dev/swiftsuspenders/swiftsuspenders/src/org/swiftsuspenders/Injector.as:134]
    at org.robotlegs.base::CommandMap/execute()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/CommandMap.as:168]
    at org.robotlegs.base::CommandMap/routeEventToCommand()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/CommandMap.as:223]
    at Function/<anonymous>()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/CommandMap.as:98]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at org.robotlegs.mvcs::Mediator/dispatch()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/mvcs/Mediator.as:89]
    at net.voxel.voxcloud.view.mediator::LoginMediator/onLogin()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/net/voxel/voxcloud/view/mediator/LoginMediator.as:32]
    at org.robotlegs.base::EventMap/routeEventToListener()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/EventMap.as:181]
    at Function/<anonymous>()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/org/robotlegs/base/EventMap.as:107]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at mx.core::UIComponent/dispatchEvent()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:13125]
    at net.voxel.voxcloud.view::LoginView/login()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/net/voxel/voxcloud/view/LoginView.mxml:32]
    at net.voxel.voxcloud.view::LoginView/___LoginView_Button1_click()[/Users/dj/Documents/new_fb_projects/VoxCloud/src/net/voxel/voxcloud/view/LoginView.mxml:74]

  11. 11 Posted by Patrick on 09 May, 2011 12:33 PM

    Patrick's Avatar

    Ok, I hacked on this all weekend - to no avail... there's some problems with injection and recursion.
    I think the issue is more with swift suspenders - I've tried various versions of swift suspenders. My next task is to create an desktop version of the same code to see if it's a problem with injection with Hero.

    I've added you as an admin on my project to help you fix your bug, to reproduce the error, uncomment out line 28 of
    https://github.com/reduxdj/VoxCLOUD/blob/master/src/net/voxel/voxcl...

    Basically the error happens when i try to inject multiple proxies or issue commands etc. Have you had any success with Hero and robot legs?

  12. Support Staff 12 Posted by Stray on 09 May, 2011 01:32 PM

    Stray's Avatar

    Hi Patrick, it turns out that it's a simple problem -

    You have your injection point in UserProxy typed as ServiceDelegate

    But your mapping is:

    injector.mapSingletonOf(IServiceDelegate,ServiceDelegate);

    This means that the injector has a rule for how to fulfil IServiceDelegate (using ServiceDelegate).

    Your injection point should always match the first parameter of the mapping.

    So - if you change your UserProxy injection point to:

    [Inject]
    public var serviceDelegate:IServiceDelegate;
    

    Then this will be fine.

    I expect you've made the same small mistake throughout your code base - if you clean all those up and then give it a go - and then come back if you still have errors.

    There's no known problem with Hero and either Robotlegs or SwiftSuspenders, so it's almost always going to be small things in your own code that are the problem (though the warnings are something we need to deal with in Robotlegs!)

    Thanks,

    Stray

  13. 13 Posted by patricklemiuex on 09 May, 2011 01:42 PM

    patricklemiuex's Avatar

    Stray,

    Thanks so much. I thought interfaces and classes were interchangeable.
    I didn't realize that small detail.
    Again thanks for the look-see.

    Patrick

  14. 14 Posted by Amy on 09 May, 2011 04:26 PM

    Amy's Avatar

    Sascha;

    I'm a bit late to the party, but you might find this post interesting if you want to build your own framework from scratch...it offers you a point of entry to get started.

    http://www.developria.com/2010/04/combining-the-timeline-with-oo.html

    Essentially, you'll want to listen for Views to be added to the stage, or you'll want to use setters to discover that a particular instance has been added and get hold of it for injection.

    This can work with MXML as well, if you're doing Flex...you simply need to think of the process described in the post as Code Behind, and it translates really well.

    HTH;

    Amy

  15. Stray closed this discussion on 25 May, 2011 08:32 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