AgE 2.5 : Describing components to be initialized by Configuration Framework

AgE configuration framework is based on Dependency Injection pattern and now it supports two kinds of injection:

  • Constructor Injection
  • Annotated Fields and Method Injection

Constructor Injection

In Constructor Injection dependencies are injected into component instance through its constructor. In more details it is described in Martin Fowler article.

All constructors which can be used during injection must be public and proceeded by @Inject annotation. From list of available constructors, the one is chosen which has the matching list of arguments types saved in configuration model (ComponentDefinition).

The following code illustrates the sample class which contains one constructor which can be used by Configuration Framework:

On this page:

package org.jage.samples;

public class Movie {

    private String title;
    private Date year;
    private Actor[] actors;

    @Inject
    public Movie(String year,
                Date year, Actor[] actors) {
        this.title = title;
        this.year = year;
		this.actors = actors;
    }
}

Annotated Fields and Methods Injection

In annotated fields and methods injection, component dependencies are injected into component instance by setting fields value or calling setter methods. Both, fields and methods, have to be proceeded by @Inject annotation.

In AgE Configuration Framework the following annotations are used:

  • @Inject - Annotates injectable constructors, methods or fields. Constructors are injected first, followed by fields and then methods. Fields and methods in superclasses are injected before those in subclasses. Type of injected component is got using reflection from field, method or constrctor parameter(s). Also name of dependent component in equal to field name or fetched from setter method (accordint to rule: setPropertyA --> propertyA)
  • @Require - Annotations which depicts if a dependent component can be nullable or not. This annotation can proceed class fields or getter methods. In the former case the result of the methods is checked.

Prior to version 2.5.0, in order to use annotated fields or methods injection, IPropertyContainer needed to be implemented and @Property used along @Inject. From version 2.5.0, this is no longer the case.

However, explicitly specifying properties in the configuration file will override annotated fields and methods injection, i.e. if you annotate a method setPropertyA but specify an explicit value for PropertyA in the configuration file, injection will not happen.The mapping between annotated members and properties is based on the standard naming convention: a field named x will be mapped to a property x, a method mapped setY()/getY() will be mapped to a property y

The following code illustrates the sample class which contains dependencies defined by annotated fields and method:

package org.jage.samples;

public class Movie implements IPropertyContainer {

    @Inject
    @Require
    private String title;

    @Inject
    private Date year;

    private List<Actor> actors;

    @Inject
    public void setActors(List<Actor> actors) {
        this.actors= actors;
    }

    @Require
    public List<Actor> getActors() {
        return this.actors;
    }
    // ...

Notes about autowiring for generic collections

jAgE supports autowiring mechanism for fields and setters/getters pairs that use generic type parameters. It means that you can define for example a parametrized list in the configuration file, like this:

<list name="long-example" type="java.lang.Long">
    <value class="Long" value="2" />
    <value class="Long" value="4" />
    <value class="Long" value="8" />
</list>

In this case, when you declare a field of the same type in the component it will be automatically injected for you:

@Inject
private List<Long> exampleList;

However, this functionality comes with some restrictions (they can be removed in future: see AGE-29):

  1. Type arguments have to be exactly the same for the definition and the declaration (i.e. the field cannot use superclass of the parameter type from the definition). Basically, this will not work for the above configuration:
    @Inject
    private List<Number> exampleList;
  2.  Wildcards are not supported and are replaced by simple Object when constructing an instance. This will not work for the above configuration:
    @Inject
    private List<?> exampleList;
  3.  "Nested" generics are not supported.The code like below cannot be used:
    @Inject
    private List<Set<Integer>> exampleList;