Error: Injector is missing a mapping to handle injection into Command

zmaldonado's Avatar

zmaldonado

14 Jul, 2014 09:16 PM

Hey, I've really been stuck on this issue for a while. I was just trying to copy the Flicker Image service project (https://github.com/lidev/robotlegs2-signals-feathers-flickr-example) but I've run into various problems with injections.

Here's the error:
Error: Injector is missing a mapping to handle injection into property "questions" of object "[object UpdateQuestionListCommand]" with type "gizmoduckdemo.controller::UpdateQuestionListCommand". Target dependency: "Array|"
at org.swiftsuspenders.typedescriptions::PropertyInjectionPoint/applyInjection()

Here's the Command class

public class UpdateQuestionListCommand extends Command
    {
        [Inject]
        public var logger:ILogger;

    [Inject]
    public var questions:Array;

    [Inject]
    public var questionListModel:QuestionListModel;

    override public function execute():void {
        logger.info( "Updating question data" );

        questionListModel.questions = questions;

    }
}</code>



Here's my config

public class GizmoDuckDemoConfiguration implements IConfig
    {
        [Inject]
        public var injector:IInjector;
        
        [Inject]
        public var mediatorMap:IMediatorMap;
        
        [Inject]
        public var commandMap:IEventCommandMap; 
        
        [Inject]
        public var logger:ILogger;
        
        public function configure():void
        {
            mediatorMap.map(ApplicationView).toMediator(ApplicationViewMediator);
            mediatorMap.map(HomeView).toMediator(HomeScreenViewMediator);
            mediatorMap.map(MainGameView).toMediator(Screen1ViewMediator);
            
            injector.map(IQuestionListService).toSingleton(XMLQuestionListService);
            
            injector.map(QuestionListModel).asSingleton();
            
            commandMap.map(RequestQuestionListLoadEvent.QUESTIONLIST_LOAD_REQUEST).toCommand(LoadQuestionListCommand);
            commandMap.map(RequestQuestionListUpdateEvent.QUESTIONLIST_UPDATE_REQUEST).toCommand(UpdateQuestionListCommand);
        }
        
        private function init():void {
            
            logger.info( "application ready" );
            
        }
    }

Here's the event that the command listens for

public class RequestQuestionListUpdateEvent extends Event
    {
        public static const QUESTIONLIST_UPDATE_REQUEST:String = "GAMELIST_UPDATE_REQUEST";
        public var data:Object;

    public function RequestQuestionListUpdateEvent(data:Object=null, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        this.data = data;
        super(QUESTIONLIST_UPDATE_REQUEST, bubbles, cancelable);
    }

    override public function clone():Event
    {
        return new RequestGameListUpdateEvent(data);
    }
}</code>



And here's the service that sends out the event

public class XMLQuestionListService implements IQuestionListService
    {
        [Inject]
        public var eventDispatcher:IEventDispatcher

    [Inject]
    public var logger:ILogger

    private var _dataXML:XML;
    private var _urlLoader:URLLoader;
    protected static const XML_PATH:String = &quot;/Users/zmaldonado/Documents/Adobe Flash Builder 4.7/MobileASQuizBang/assets/sample.xml&quot;;

    public function XMLQuestionListService()
    {
        _urlLoader = new URLLoader();
    }

    public function loadQuestions():void
    {
        var xmlFile:File = new File(XML_PATH);
        trace(xmlFile.nativePath);
        var fileStream:FileStream = new FileStream();
        fileStream.open(xmlFile, FileMode.READ);
        var str:String = fileStream.readUTFBytes(xmlFile.size);
        fileStream.close();
        _dataXML = new XML(str);
        //trace(str);
        var sheet:XMLList = _dataXML.*;

        const questionList:Array = new Array();
        for(var i:int = 0; i &lt; sheet.*.length(); i++)
        {
            var row:XML = sheet.*[i];

            var question:QuestionVO = new QuestionVO(
                    row.questionid,
                    row.zone_name,
                    row.difficulty,
                    row.question,
                    row.Wrong_answer1,
                    row.Wrong_answer2,
                    row.Wrong_answer3,
                    row.CORRECT
                    );

            trace(question);
            questionList.push(question);
        }

        eventDispatcher.dispatchEvent(new RequestQuestionListUpdateEvent(questionList));
        //eventDispatcher.dispatchEvent(new RequestGameListUpdateEvent(widgetItems));
    }
}</code>



Here's the model

package gizmoduckdemo.model
{
    import flash.events.IEventDispatcher;

public class QuestionListModel
{
    [Inject]
    public var eventDispatcher:IEventDispatcher;

    private var _questions:Array;

    public function set questions( value:Array ):void {
        _questions = value;
    }

    public function get questions():Array {
        return _questions;
    }
}



}

Here's the QuestionVO. If you don't have the xml, it won't really matter I guess

public class QuestionVO
    {
        private var _questionid:Number;
        private var _zone_name:String;
        private var _difficulty:int;
        private var _question:String;
        private var _wrong1:String;
        private var _wrong2:String;
        private var _wrong3:String;
        private var _correct:String;

    public function QuestionVO(...params)
    {
        _questionid = params[0];
        _zone_name = params[1];
        _difficulty = params[2];
        _question = params[3];
        _wrong1 = params[4];
        _wrong2 = params[5];
        _wrong3 = params[6];
        _correct = params[7];
    }

    public function get questionid():Number
    {
        return _questionid;
    }

    public function get zone_name():String
    {
        return _zone_name;
    }

    public function get difficulty():int
    {
        return _difficulty;
    }

    public function get question():String
    {
        return _question;
    }

    public function get wrong1():String
    {
        return _wrong1;
    }

    public function get wrong2():String
    {
        return _wrong2;
    }

    public function get wrong3():String
    {
        return _wrong3;
    }

    public function get correct():String
    {
        return _correct;
    }

    public function toString():String
    {
        return &quot;&quot; + _questionid + &quot;, &quot; + _zone_name + &quot;, &quot; +  _difficulty + &quot;, &quot; +  _question + &quot;, &quot; +  _wrong1 + &quot;, &quot; +  _wrong2 + &quot;, &quot; +  _wrong3 + &quot;, &quot; +  _correct;
    }
}</code>



I have no idea why I'm getting this error. The only thing I can think is that I need to specifically inject an array into the command but that doesn't quite make sense and I don't believe the Flickr project had to do anything like that. It's just worked when they did it with a Vector (I should note that I tried doing this with a vector and still got the same error)

  1. Support Staff 1 Posted by Ondina D.F. on 15 Jul, 2014 07:14 AM

    Ondina D.F.'s Avatar

    Hi Zack,

    The example is using Signals and the SignalCommandMap, which allows the injection of Signal's parameters into a command.

    https://github.com/lidev/robotlegs2-signals-feathers-flickr-example...

    i.e. GalleryItemVO into UpdateGalleryCommand

    As I can see you're using a regular commandMap with events.

    You're dispatching an event with an array as a payload in your service class:

    eventDispatcher.dispatchEvent(new RequestQuestionListUpdateEvent(questionList));

    In your command you need to inject the event if you want to access its payload:

    [Inject]
    public var event: RequestQuestionListUpdateEvent;
    
    public function execute():void 
    {
        questionListModel.questions = event.data;
    }
    

    Hope that helps.

    Ondina

  2. 2 Posted by zmaldonado on 15 Jul, 2014 02:07 PM

    zmaldonado's Avatar

    That works! So, now my command class looks like this.

    public class UpdateQuestionListCommand extends Command
        {
            [Inject]
            public var logger:ILogger;
            [Inject]
            public var questionListModel:QuestionListModel;
            [Inject]
            public var event:RequestQuestionListUpdateEvent;
            override public function execute():void 
            {
                questionListModel.questions = event.data as Array;
            }
        }
    

    Thank you so much, Ondina!

  3. 3 Posted by zmaldonado on 15 Jul, 2014 02:20 PM

    zmaldonado's Avatar

    I should note that I think that specific error was coming up because of the code

    [Inject]
        public var questions:Array;
    
    in my command, which doesn't really make sense.
  4. Support Staff 4 Posted by Ondina D.F. on 16 Jul, 2014 08:46 AM

    Ondina D.F.'s Avatar

    You're welcome, Zack!

    [Inject] public var questions:Array;

    Yes, you're right, it doesn't make much sense.

    First of all, having an injection point (the [Inject] metadata tag ) without a rule (mapping) would result in an error, like the one you've encountered:
    Injector is missing a mapping to handle injection into property....

    I wasn't sure how much you already knew about how injection works, that's why I didn't give you more explanations :)
    You can take a look at these discussions for more details about injection rules and injection points:
    http://knowledge.robotlegs.org/discussions/robotlegs-2/8182-the-nec...

    http://knowledge.robotlegs.org/discussions/robotlegs-2/5766-automag...

    So, the rule would be:

    var somePrimitive:String = new String();
    somePrimitive = "someValue";
    injector.map(String).toValue(somePrimitive);
    

    Now, the injection would occur.

    But, there are a few problems with this kind of injection.

    Say, you wanted to have another String as well to be injected somewhere. You'd map it like this:

    var anotherPrimitive:String = new String();
    anotherPrimitive = "anotherValue";
    injector.map(String).toValue(anotherPrimitive);
    

    But, the Injector would immediately complain about the confusing mappings:
    Injector mapping override for type...

    The solution would be to use named mappings and injections:

    var somePrimitive:String = new String();
    somePrimitive = "someValue";
    injector.map(String, "firstPrimitive").toValue(somePrimitive);
    
    var anotherPrimitive:String = new String();
    anotherPrimitive = "anotherValue";
    injector.map(String,  "secondPrimitive").toValue(anotherPrimitive);
    

    And you'd inject them like this:

    [Inject (name="firstPrimitive")]
    public var somePrimitive:String;
    
    [Inject (name="secondPrimitive")]
    public var anotherPrimitive:String;
    

    As you can see, injecting primitives (String, Number, int, Boolean, etc) or collections (Array, Vector, List) is possible, but it requires more work and it is prone to errors (typos when you use named injection, for example).

    The recommended practice is to avoid injecting primitives whenever possible and to use strongly typed wrappers instead:
    A VO with firstPrimitive and secondPrimitive as properties, for example, that can be injected where needed or used as a signal's or event's payload, depending on the use case...

    Don't hesitate to ask more questions, in case my explanation wasn't clear enough.

    Ondina

  5. 5 Posted by zmaldonado on 16 Jul, 2014 03:34 PM

    zmaldonado's Avatar

    Awesome! Your explanation was great, Ondina. A VO is certainly good at that sort of wrapping, and I've been using a view in my program for storing data and what not, but I can see how just trying to deal with primitive can end up being a pain in the neck . But it is possible at least. Thank you for the help!

  6. Support Staff 6 Posted by Ondina D.F. on 17 Jul, 2014 11:50 AM

    Ondina D.F.'s Avatar

    Thanks! I'm glad it was helpful. I'm going to mark this thread as resolved. If you have more questions regarding this topic, you can re-open the discussion at any time.

    See you around:)
    Ondina

  7. Ondina D.F. closed this discussion on 17 Jul, 2014 11:50 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