Skip to content
Ondina edited this page May 5, 2012 · 18 revisions

Here’s a list of some commonly recurring problems that people face when getting started with Robotlegs.

  1. Problem: Injection Doesn’t Occur
  2. Problem: Things Work For A While And Then Mysteriously Stop
  3. Problem: Event Dispatch Doesn’t Work As Expected
  4. Problem: Mediator Not Running onRegister
  5. Error: Call to a possibly undefined method X
  6. Error: Injector missing rule for X
  7. Other Problems

Problem: Injection Doesn’t Occur

Incorrect Injection Point Declaration

Here is how a correctly defined property injection point looks:

[Inject]
public var someValue:SomeType;

Note: the injected property must be public. This is wrong:

[Inject]
private var someValue:SomeType;

Note: Metadata is case-sensitive. These are wrong:

[inject]
[INJECT]
[InJect]

Note: A semi-colon after your [Inject] will stop it working. This is wrong:

[Inject];
public var someValue:SomeType;

Incorrect injection point declaration won’t throw errors, your application just won’t work correctly.

Metadata Stripping

The Flash/Flex compiler will strip out non-standard metadata unless you tell it not to – this includes the [Inject] and [PostConstruct] metadata that Robotlegs needs to function correctly. Sometimes, when building an AIR application for example, the metadata will stay intact while debugging but will be stripped out when you publish your release build. You need to tell the compiler that you want it to keep the [Inject] and [PostConstruct] metadata tags.

The Robotlegs SWC includes the required compiler arguments for you, but when linking against the source you will need to add the arguments yourself:

Flex/FlashBuilder Solution

Right-click your project and click Properties. Go to “Flex Compiler”, and under “Additional compiler arguments” add:

-keep-as3-metadata+=Inject -keep-as3-metadata+=PostConstruct

Note: This is not necessary if you are compiling against the Robotlegs SWC. The SWC includes these arguments for you.

Flash IDE Solution

Select “Export SWC” in your publish settings. This will force the Flash compiler to keep all metadata intact.

Injected Properties Are Null In Constructor

Dependencies injected via setter/property injection are not available until after the instance has been created – it’s pretty easy to visualize, just imagine doing it by hand: first you create the new instance and then you set the properties.

PostConstruct Solution

The most common solution to this problem is to remove the code from your constructor and place it into a public method with [PostConstruct] metadata placed above it, like so:

[PostConstruct]
public function init():void
{
    // all dependencies have now been satisfied
}

Note: [PostConstruct] metadata is case-sensitive.

Constructor Injection Solution

Instead of using property/setter injection you can use constructor injection, simply define your dependencies as constructor arguments.

A word of warning about constructor injection: Due to a bug in the Flash Player (pre 10.1), full type information for constructor arguments is only available after the affected class has been instantiated at least once. To work around this bug, SwiftSuspenders (the default DI/IoC framework that Robotlegs uses) checks if type information for the arguments is available when performing constructor injection. If not, SwiftSuspenders will create one throw-away instance of the class. Because of this behavior, it is important not to start any complex processes in constructors of classes that are used with constructor injection.

Problem: Things Work For A While And Then Mysteriously Stop

Make sure to hang on to your context! We’ve seen a lot of people make this simple mistake. Consider the following (the WRONG way):

public class HelloActionScript extends Sprite
{
	public function HelloActionScript()
	{
		var context:HelloContext = new HelloContext( this );
	}
}

The problem here is that the context is scoped as a local variable, and as such it will be free for Garbage Collection pretty much straight away. The context might function for a little while, but at some point in time it will be GC’d and cease to exist.

Solution – Hang on to your context!

public class HelloActionScript extends Sprite
{
	private var context:HelloContext;

	public function HelloActionScript()
	{
		context = new HelloContext( this );
	}
}

Note: keep a reference to your context instance.

Problem: Event Dispatch Doesn’t Work As Expected

Make sure to override the clone() method of your custom event class. Events can not be re-dispatched without doing so – even non-bubbling events. It is considered best practice when creating custom events to override clone().

Problem: Mediator Not Running onRegister

Check: Have you created a mapping for this view-mediator pair? All mappings need to be provided manually.

Check: Is your view being added to the stage? The mediator onRegister() method runs after the view has landed on stage. It’s possible to addChild(view) without the view actually being added to the stage, if the parent is not on stage.

Check: If your view is definitely mapped to the mediator and is definitely being added to the stage: has your view hit the stage before the mapping was made?

Note: Generally you should aim to list your mediator mappings from the inside out – map the most deeply nested view first, and your contextView last. This ensures that if you have an init() function in your parent view that adds the internal children, and is triggered by the onRegister of the parent mediator, all the child mappings will already have been made before this code runs, and your views won’t hit the stage before their mappings have been made.

Error: Call to a possibly undefined method X

Among other reasons this error could be the result of not following the AS3 naming conventions for packages, classes, methods, variables, and so on.

For example something like this:

package controller 
{
	import model.MyModel;
	import org.robotlegs.mvcs.Command;
	
	public class MyCommand extends Command
	{
		[Inject]
		public var model:MyModel;
		
		[Inject]
		public var event:MyEvent;
		
		override public function execute():void
		{
			model.myMethod();
		}
	}
}

would result in: Error 1180: Call to a possibly undefined method myMethod

and eventually a warning (depending on the SDK):

Warning 3599: Definition name is the same as an imported package name.
Unqualified references to that name will resolve to the package and not the definition. If a definition is named the same as a package that is in scope, then any unqualified references to that name will resolve to the package instead of the definition. This can result in unexpected errors when attempting to reference the variable. Any references to the definition need to be qualified to resolve to the definition and not the package.

Solution – Package your classes properly

This would be incorrect: model.SomeModel
This would be better: domain.project.area.model.SomeModel

It wouldn’t hurt to read the Coding Conventions again (and again and again).

Error: Injector missing rule for X

Missing Injection Mapping

The injector needs to be provided with a rule about how to fulfil each injection. If you have an [Inject] point, you must have a corresponding mapping on the injector, either directly through the injector mapping methods or through the commandMap, viewMap and mediatorMap.

Inconsistent Injection Mapping

Remember that if you’ve mapped a class using mapSingletonOf then you must inject using the first parameter and not the concrete class.

injector.mapSingletonOf(ISomeType, SomeType);
injector.mapSingletonOf(BaseSomeType, SpecialSomeType);

So, these injections will be fine:

[Inject]
public var someValue:ISomeType;

[Inject]
public var someOtherValue:BaseSomeType;

But these injections will produce an injection error:

[Inject]
public var someValue:SomeType;

[Inject]
public var someOtherValue:SpecialSomeType;

Other Problems

Please visit knowledge.robotlegs.org