4 Dependency Injection

Defining the dependencies of your classes is one of the core tasks when you configure
the services and actions of your application. This chapter demonstrates the various options
Parsley offers you for Dependency Injection.

The preferred configuration style for dependencies is using AS3 Metadata tags.
Since the dependencies of a class are part of the core aspects of a class definition
it makes sense to define dependencies right in the ActionScript class itself.
It some cases you may still prefer to externalize dependency declarations, the corresponding options
are described in the final section of this chapter 4.5 Declaring Dependencies in MXML or XML.

4.1 Constructor Injection

Many consider this to be the cleanest injection style in terms of encapsulation, since it allows
you to create immutable classes. Since (unfortunately) the Flash Player currently ignores metadata tags
placed on constructors you have to place a [InjectConstructor] tag on the class declaration to tell Parsley
to perform Constructor Injection:

Note that in the example above the manager parameter is optional. Parsley reflects on this
information and uses it as a hint whether the defined dependency is required or optional.
So in this case the container will throw an error if it does not contain an object of type LoginService,
but it will simply silently ignore the second parameter if the Context does not contain an object of type UserManager.

Constructor injection selects the dependencies based on the parameter types. This means that it only works for dependencies
where you know that the Context will always contain at most one object with a matching type. It is also good practice to use
interfaces as parameter types so that you can switch implementations in the configuration without modifying the class.

As explained in 3.2 MXML Configuration you cannot use simple MXML tags for configuration if you want to use Constructor Injection
since in that case the MXML compiler generates the object creation code and Parsley only gets hold of the object after
it was instantiated to perform additional configuration. So instead of defining such a class like this:

When using Parsley's Object tag it's the framework that is responsible for instantiating the object so that
Constructor Injection can be performed.

There are no restrictions when you are using XML configuration.

Unfortunately there is a nasty bug in some Flash Player versions where reflection on constructor parameter types using
describeType does not work properly (the Player always reports '*' as the type in these cases.
If you run into this bug the only workaround (unfortunately) is to create instances of these classes before you initialize
Parsley:

new LoginAction();
new ShoppingCartAction();

You can simply throw away these instances, just creating an instance "fixes" describe type for the parameter types of that class.

4.2 Method Injection

Method Injection is similar to Constructor Injection. You can place [Inject] metadata tags on any number of methods:

As with Constructor Injection Parsley will recognize whether a method parameter is optional or not and
accordingly treat the dependency as optional or required. The object to be injected will be selected by type, so you
should make sure to include at most one object with a matching type into your configuration. For Method Injection
there are no restrictions on MXML configuration, so in contrast to Constructor Injection you could also use
simple MXML tags for adding the objects to the container.

4.3 Property Injection by Type

This injection mechanism is simliar to Method Injection, but is performed for properties instead:

You can place the [Inject] tag on a var declaration or a setter function. For properties Parsley cannot
detect whether the dependency is optional or not so you can explicitly set it with the required attribute.
The default is true if the attribute is omitted.

Like with Constructor or Method Injection shown above this mode select dependencies by type. So again you should
make sure to include at most one object with a matching type into your configuration.

4.4 Property Injection by Id

Instead of letting the container select the dependency by type you can alternatively explicitly set the id
of the object to inject:

[Inject(id="defaultLoginService")]
public var service:LoginService;

In this case Parsley will select the dependency by id so the configuration has to include an object
with a corresponding id:

Often it's not the best idea to include configuration artifacts like ids into your class files.
Inject metadata tags are usually more appropiate for injection by type like demonstrated in previous sections.
If you have to set the id of a dependency explicitly it is often preferrable to externalize it to MXML or XML
configuration like shown in the next section.

As you see MXML and XML configuration is almost identical except for some subtle notation differences
(capitalized camel-case vs. lower case names with dashes). You can set dependencies for constructor arguments
or properties. For constructor arguments you could even mix it with tags for simple properties:

Note that you cannot set an id for an inline object definition. The MXML example would be analogous.

4.6 Overriding Dependencies in Child Contexts

Whenever you inject by type and the dependency is not optional the Context must contain exactly one instance
of a matching type. If the dependency is missing or ambiguous (with more than one matching type) the Context will
throw an error.

Nevertheless, in an application with more than one Context you have the option to "override" a dependency
in a child Context without causing these errors for ambiguous dependencies. This allows for more flexibility.
You could, for example, add a default implementation of an interface to the root Context and still leave it up
to a loaded module to install alternatives themselves.

When you declare a dependency by type the framework will look up this type in the Context the dependent
object belongs to first. Only if no matching instance is found it will look up the next parent in the Context
inheritance tree. This also means that the overriding only affect the objects in the child Context. It does
not mean that the dependency in the parent Context gets "uninstalled". It will still be used for injections
into other objects in the parent Context. So the overriding is always interpreted as a local override, not
a global one.

This mechanism helps to avoid using string identifiers in [Inject] tags even though you
want to add different implementations of the same interface to different child Contexts. Only when you add
multiple implementations to the same Context, you must switch to using injection by id to avoid errors.

You can also add overrides for injection by id in a similar way. It is not allowed to have two or more#
objects with the same id within a single Context, but it is legal to add an object with an id that is already
present in a parent Context.