Injection error when injecting one Actor into another

Josh's Avatar

Josh

15 Nov, 2012 12:06 AM

This is a difficult problem to explain, but I'll give it a go. I have a factory class (extends Actor) that has need to retrieve some values from a Model (obviously also an Actor). I've certainly done this scenario a million times, but in this case, the Injection is throwing a rather catastrophic, undefined error.

I have plenty of examples in my codebase of Factory classes injecting models, but I can't seem to see a difference in usage with this one. Baffling. The error is pasted at the end of this post.

Anyone seen this sort of error before, and if so, any thoughts on what root cause might be?

undefined

at org.robotlegs.mvcs::Actor()[/Users/jettwein/Documents/svn-repositories/pmp_ui/src/org/robotlegs/mvcs/Actor.as:52]
at com.foo.bar.model::ExhibitionModel()[/Users/jettwein/Documents/svn-repositories/pmp_ui/src/com/foo/bar/model/ExhibitionModel.as:145]
at org.swiftsuspenders.injectionpoints::NoParamsConstructorInjectionPoint/applyInjection()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/injectionpoints/NoParamsConstructorInjectionPoint.as:21]
at org.swiftsuspenders::Injector/instantiate()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/Injector.as:138]
at org.swiftsuspenders.injectionresults::InjectSingletonResult/createResponse()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/injectionresults/InjectSingletonResult.as:40]
at org.swiftsuspenders.injectionresults::InjectSingletonResult/getResponse()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/injectionresults/InjectSingletonResult.as:31]
at org.swiftsuspenders::InjectionConfig/getResponse()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/InjectionConfig.as:43]
at org.swiftsuspenders::InjectionConfig/getResponse()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/InjectionConfig.as:49]
at org.swiftsuspenders.injectionpoints::PropertyInjectionPoint/applyInjection()[/Development/Projects/SwiftSuspenders/src/org/swiftsuspenders/injectionpoints/PropertyInjectionPoint.as:36]
  1. Support Staff 1 Posted by Ondina D.F. on 15 Nov, 2012 10:26 AM

    Ondina D.F.'s Avatar

    Hi Josh,

    Of course it would be good to see some code: mappings, injections into your actor class…, what does your factory class look like?
    From the error you’re getting, I guess it has something to do with some sort of constructor injection.

    First take a look at these:

    https://github.com/robotlegs/robotlegs-framework/wiki/common-proble...

    http://shaun.boyblack.co.za/blog/2009/05/01/constructor-injection-v...

    Some questions:

    Is your Model mapped as a singleton?
    Are you injecting it using [Inject]?
    Are you creating a new instance of that Model?
    Are you using setters and getters?
    Are you accessing the Model in the constructor of the other class?

    If you can’t figure it out, just paste some relevant code or attach a simplified example reproducing the issues.

    Ondina

  2. Support Staff 2 Posted by Ondina D.F. on 15 Nov, 2012 04:32 PM

    Ondina D.F.'s Avatar

    To sum it up:

    1- Check if the classes that need to be injected have been mapped
    No mapping=No Injection (Injector is missing a rule to handle injection into target)

    2- Make sure the mappings occur before the injection
    Mapping first, Injection second (Cannot access a property or method of a null object reference.)

    3- Make sure you have the correct injection point declaration / see Common Problems: Incorrect Injection Point Declaration

    4- Make sure the class needing an injection has been constructed before trying to access the injected properties – properties are null in the constructor

    5- Try to avoid doing work in constructors

    Situations where injection doesn’t work:

    A.

    Accessing the injected properties in the constructor

    Context:
    injector.mapSingleton( AnotherModel);//to be injected into SomeModel
    injector.mapSingleton(SomeModel);

    SomeModel.as

    [Inject]
    public var _anotherModel:AnotherModel;
        
    public function SomeModel()
    {
          trace(_anotherModel.aProperty);
    }
    

    AnotherModel is null in the constructor (Error: Cannot access a property or method of a null object reference.)

    [PostConstruct]
    public function someInit():void
    {
          trace(anotherModel.aProperty);
    }
    

    In someInit, AnotherModel is not null.

    B.

    There are no mappings for AnotherModel in the context, and you try to pass AnotherModel as a parameter on to SomeModel’s constructor, but constructor injection fails without mapping AnotherModel in the context.

    public class SomeCommand extends Command
    {
          public var anotherModel:AnotherModel;//no inject tag
            
           [Inject]
          public var someModel:SomeModel;
    
    override public function execute():void
    {
          anotherModel=new AnotherModel();
          anotherModel. aProperty ="data set in a command";
          someModel =new SomeModel (anotherModel);
          someModel.someMethod("someString");
    }
    

    SomeModel.as

    public var _anotherModel:AnotherModel;//no inject tag
        
    public function SomeModel(anotherModel:AnotherModel)
    {
          _anotherModel= anotherModel;
          trace(_anotherModel.aProperty);
    }
    [PostConstruct]
    public function someInit():void
    {
          _anotherModel.someData="data set in a post construct method";
          trace ("someInit"+_anotherModel. aProperty);
    
    }
    public function someMethod(value:String):void
    {
          trace("someMethod "+_anotherModel. aProperty);
    }
    

    Error: Injector is missing a rule to handle injection into property "anotherModel" …

    What I would do:
    1-Context:
    injector.mapSingleton( AnotherModel);//to be injected into SomeModel
    injector.mapSingleton(SomeModel);
    2- trigger the command after mappings are done
    3- Command

    public class SomeCommand extends Command
    {
           [Inject]
          public var anotherModel:AnotherModel;
            
           [Inject]
          public var someModel:SomeModel;
    
    override public function execute():void
    {
          anotherModel. aProperty ="data set in a command";
          someModel.someMethod("someString");
    }
    

    4-Model
    SomeModel.as

    [Inject]
    public var _anotherModel:AnotherModel;
        
    public function SomeModel()
    {
          //**NOTHING**
    }
    [PostConstruct]
    public function someInit():void
    {
    //I wouldn’t use PostConstruct, but it’s a possible solution
          _anotherModel.someData="data set in a post construct method";
          trace ("someInit"+_anotherModel. aProperty);
    
    }
    public function someMethod(value:String):void
    {
          trace("someMethod "+_anotherModel. aProperty);
          _anotherModel. aProperty=value; 
    }
    

    Ondina

  3. 3 Posted by Josh on 15 Nov, 2012 06:00 PM

    Josh's Avatar

    Thanks, Ondina, for the long reply.

    To answer your questions:
    1) Is your Model mapped as a singleton? YES
    2) Are you injecting it using [Inject]? YES
    3) Are you creating a new instance of that Model? NO
    4) Are you using setters and getters? YES, in the model that is being injected. Is this an issue? I have another Model being injected into this Factory class, and that one also has get/set methods, and that injection is not throwing errors, and the getter method is being used in the class it's injected into. I'm doubting that's the issue.
    5) Are you accessing the Model in the constructor of the other class? NO. As a rule, I stay away from code in constructors.

    Here's a look at the injection:

    public final class FilmDetailsParser extends Actor {
            
    
            //[Inject]
            //public var applicationStateModel:ApplicationStateModel;
            
            [Inject]
            public var remoteControlMenuModel:RemoteControlMenuModel;
            
            
            private var _exhibition:        ExhibitionVo;
            private var _title:             TitleVo;
            
            // LoaderMax instance
            private var _actorsXMLArray:    Array;
            private var _writersXMLArray:   Array;
            private var _directorsXMLArray: Array;
            
            private var _loaderQueue:       LoaderMax;
            
            private var _actors:            Vector.<PersonVo>;
            private var _writers:           Vector.<PersonVo>;
            private var _directors:         Vector.<PersonVo>;
            private var _genres:            Vector.<GenreVo>;
            private var _ratings:           Vector.<RatingVo>;
            
            
            
            public function FilmDetailsParser() {}
    

    Note, that if the injection of "applicationStateModel" above is uncommented, this is when the error occurs.

    This is how the injected Model needs to be used:

    var stateObject:Object = applicationStateModel.stateObject; 
    // This is via public getter on the ApplicationStateModel for private var _stateObject
    

    Of note is that the error occurs virtually immediately upon attempting to run the SWF, and the error is also shown as "undefined", with no indication of a class file that contains the error (at least not outside of RL core files) nor any of the normal Injection errors.

  4. Support Staff 4 Posted by Ondina D.F. on 15 Nov, 2012 06:36 PM

    Ondina D.F.'s Avatar

    Hey Josh,

    I’m about to go offline, so I don’t have much time for investigating your code.
    Some quick thoughts, though:
    Is applicationStateModel.stateObject something you’re innjecting into ApplicationStateModel or is it a normal property?
    Maybe you forgot to map it as an interface, in case ApplicationStateModel is implementing one?

    Can you paste some code from ApplicationStateModel? I guess, there is something not quite right.

    Till tomorrow..
    Ondina

  5. 5 Posted by Josh on 15 Nov, 2012 06:49 PM

    Josh's Avatar

    applicationStateModel.stateObject is a private variable on ApplicationStateModel with a public getter method. I can paste some code from the ApplicationStateModel, but there's not a lot there that will be helpful. I feel as though there is some sort of circular reference going on here, where one class is injecting another is injecting another and it can't sort out the chain, but I'm not sure what that would be.

  6. Support Staff 6 Posted by Ondina D.F. on 16 Nov, 2012 11:01 AM

    Ondina D.F.'s Avatar

    Hi Josh,

    I feel as though there is some sort of circular reference going on here, where one class is injecting another is injecting another and it can't sort out the chain, but I'm not sure what that would be.

    Oh, yes, that could cause problems. But without seeing the code I can’t help you.
    There are 2 options:
    -Either you figure it out by yourself, maybe through using the debugger, trace or log statements, or by reducing the complexity of the classes in question and adding functionalities one by one

    -Or, you can attach the app, and I can take a look at it. If you want, I (or you) can make the discussion private and after I dl-ed the code I delete the attachment and make the discussion public again.

    Ondina

  7. Support Staff 7 Posted by Ondina D.F. on 20 Nov, 2012 10:11 AM

    Ondina D.F.'s Avatar

    Josh, I guess you solved your problem, thus I’m closing the discussion for now, but you can re-open it, if need be.

  8. Ondina D.F. closed this discussion on 20 Nov, 2012 10:11 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