Adapting own Framework to RobotLegs

sascha's Avatar

sascha

10 Jun, 2010 02:47 PM

I'm just getting my feet wet with RL but I have a bit of a trouble to understand how I should utilize RL to adapt to my own framework. Basically I have some view classes which were Singletons in the earlier version of my framework and I want to map them as Singletons with RL but if I try that the classes are not instantiated by RL and I get a null ref exception thrown. Also, is it possible to map a Context class as a Singleton?

  1. Support Staff 1 Posted by Till Schneidere... on 10 Jun, 2010 03:09 PM

    Till Schneidereit's Avatar

    Robotlegs doesn't make using singleton views easy, that's true. But
    that's also something you should try to avoid if at all possible.

    Without knowing the specifics of your setup, it sounds to me like the
    easiest way to adapt your architecture would be to introduce a
    singleton view registry with which you can register your views. Then
    mediate the "singleton" views as all others but register them with the
    registry over which they can be accessed by all interested parties.

    Mapping a Context (or whatever else) class as a singleton is as easy as
    injector.mapSingleton(Context);

  2. 2 Posted by sascha on 10 Jun, 2010 03:43 PM

    sascha's Avatar

    Thanks a lot for the explanation! If I think about it there's only really one view class that was a Singleton which happens to be a (debug) console class to that logging output is sent. I suppose it wouldn't hurt too much to not map it as a Singleton but instead create a Mediator for it?!

    About the Singleton Context ... I have a class named Main which is my Context. I've mapped it with:

    injector.mapSingleton(Main);

    ... inside the Main class' startup() and injected it into a view class that has a mediator mapped to it. Now in the mediator I'm trying to access a property of the Main class (in the view class I can't /shouldn't inject Main if I see that right?) but if I try that I get the following exception:

    InjectorError: Injector is missing a rule to handle injection into target [class Main]. Target dependency: flash.display::Sprite, method: constructor, parameter: 1

    The Main class constructor has a parameter of type Sprite (which becomes the contextView). Any ideas?

  3. Support Staff 3 Posted by Till Schneidere... on 10 Jun, 2010 05:10 PM

    Till Schneidereit's Avatar

    You should create a mediator for that debug console, right. Maybe
    create an accompanying DebugConsoleModel which you register the
    mediator with or something similar.

    The reason for your singleton mapping of Main not working is that the
    injector can't construct the singleton instance. That's because it
    doesn't know how to supply the dependency your Main class's
    constructor has: the Sprite. To make it work, you can do one of two
    things:

    1. create the instance eagerly in your startup method, supplying the
    contextView manually. Then you can use mapValue, resulting in that
    same value being returned each time the type Main is required for
    injection.

    2. change the type your Main class's constructor expects to
    DisplayObjectContainer - that's the type by which the contextView is
    mapped by default.

  4. 4 Posted by sascha on 10 Jun, 2010 05:43 PM

    sascha's Avatar

    Ok I've tried your second suggestion, changing the constructor argument to type DisplayObjectContainer but instead of the former error I'm now getting a Stack Overflow Exception.

    About solution Nr. 1 ... but actually the Main class is already existing. I map it (as mentioned above) to Singleton inside its own startup() method and the view class. This is how my Main class looks:

    ` public class Main extends Context
    {

    private var _config:Config;
    private var _applicationUI:ApplicationUI;
    
    public function Main(app:DisplayObjectContainer)
    {
        super(app, true);
    }
    
    override public function startup():void
    {
        _config = new Config();
    
        injector.mapSingleton(Main);
        mediatorMap.mapView(ApplicationUI, ApplicationUIMediator);
    
        _applicationUI = new ApplicationUI();
        contextView.addChild(_applicationUI);
    
        super.startup();
    }
    
    public function get config():Config
    {
        return _config;
    }
    

    } `

    And here's my view mediator:

    ` public class ApplicationUIMediator extends Mediator
    {

    [Inject]
    public var _main:Main;
    [Inject]
    public var _applicationUI:ApplicationUI;
    
    override public function onRegister():void 
    {
        super.onRegister();
        trace(_main.config.consoleKey);
    }
    

    } `

  5. Support Staff 5 Posted by Till Schneidere... on 10 Jun, 2010 05:56 PM

    Till Schneidereit's Avatar

    Aha, I didn't understand that Main is extending Context!

    In that case, just use
    injector.mapValue(Main, this);

  6. 6 Posted by sascha on 10 Jun, 2010 06:18 PM

    sascha's Avatar

    Ok that did it! Even though Main is now not mapped as a Singleton anymore. But I guess I can live with that.

    Thanks for your time and help! :)

  7. Support Staff 7 Posted by Joel Hooks on 10 Jun, 2010 08:54 PM

    Joel Hooks's Avatar

    Main is effectively mapped as a context managed Singleton. Unless you override that mapping later, only the one instance is available for injection.

  8. 8 Posted by sascha on 11 Jun, 2010 02:59 AM

    sascha's Avatar

    Good to know that, thanks Joel! I was wondering if Context classes get a special treatment like that.

  9. Support Staff 9 Posted by Till Schneidere... on 11 Jun, 2010 10:13 AM

    Till Schneidereit's Avatar

    I'm not sure you're saying that, but just to make sure: Context
    doesn't get any special treatment at all. In fact, no other class in
    the framework even knows about or ever even gets a reference to the
    context - it's just something similar to a main entry point that kicks
    things off.

    What actually happens is that mapValue causes the injector to always
    return that same value for each request. That means that ultimately,
    mapValue works the same as mapSingleton does, with the only difference
    being that singleton mappings don't create the singleton instance
    until it is actually requested for the first time.

  10. 10 Posted by sascha on 11 Jun, 2010 12:09 PM

    sascha's Avatar

    Yes, I didn't want to imply that a Context get's a special treatment as in "being treated as a Singleton". i guess my quote above is misleading.

    I got another small question: How do I inject a static class? I have one class which has only static methods and in this class I need access to two other classes which are mapped. I injected these two in the static class as static properties but how do I get RL to map the static class?

  11. Support Staff 11 Posted by Till Schneidere... on 11 Jun, 2010 03:08 PM

    Till Schneidereit's Avatar

    You can neither inject into static fields of a class, nor can you map
    the class itself to anything but "Class". The first of these you
    should not do anyway: Static state should be avoided if in any way
    possible at all. The second just doesn't work. For example, "MyClass"
    is an instance of the class "Class", so all you could do would be to
    use injector.mapValue(Class, MyClass), but I guess that's not what you
    imagined.

    I would recommend changing your class to not use static state and
    methods and inject an instance of it using mapSingleton or mapValue.

    If you've got any further questions about this, please open a new
    topic, as this is really unrelated to the topic discussed here
    earlier. Thus, I'm closing this thread now.

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