annotation_configuration

Aedi, a dependency injection library.

Aedi is a dependency injection library. It does provide a set of containers that do IoC, and an interface to configure application components (structs, objects, etc.)

Aim:

The aim of library is to provide a dependency injection solution that is feature rich, easy to use, easy to learn, and easy to extend up to your needs.

Code api, offers a rich set of functionality, and flexibility. Though alternatives to configuring a container with components should be provided along with their strengths and disadvantages. For this purpose as an alternative to code api, the framework implements annotation based configuration of components.

The main idea of annotation based configuration of components is that, information about component's dependencies and configuration properties are stored in form of annotations right in it. The framework does provide annotation based counterparts of almost all configuration primitives available in code api. Example below shows a component configured using annotation based information:

1 @component // Mark component to be registered in container
2 @qualifier("custom.identity") // Specify custom identity for component in container instead of it's type as identity
3 class Car {
4 
5     // ...
6 
7     public {
8 
9         @constructor(lref!Size, lref!Engine) // Construct this component using arguments passed to constructor annotation
10         this(Size size, Engine engine) {
11             this.size_ = size;
12             this.engine = engine;
13         }
14 
15         @property {
16 
17             @setter("color.green".lref) // Set the property to arguments passed in setter
18             Car color(Color color) @safe nothrow {
19             	this.color_ = color;
20 
21             	return this;
22             }
23 
24             // ...
25 
26             @setter(lref!Engine) // Set the property to arguments passed in setter
27             Car engine(Engine engine) @safe nothrow {
28             	this.engine_ = engine;
29 
30             	return this;
31             }
32 
33             // ...
34 
35             @autowired // Automatically wire property using components from container identified by their types
36             Car frontLeft(Tire frontLeft) @safe nothrow {
37             	this.frontLeft_ = frontLeft;
38 
39             	return this;
40             }
41 
42             // ...
43 
44             @callback(
45                 function (Locator!() locator, ref Car configured) {
46                     configured.frontRight = locator.locate!Tire;
47                 }
48             ) // Use a callback to configure the property, or entire object. Can be attached anywhere on component
49             Car frontRight(Tire frontRight) @safe nothrow {
50             	this.frontRight_ = frontRight;
51 
52             	return this;
53             }
54 
55             // ...
56 
57             @autowired // Automatically wire property using components from container identified by their types
58             Car backLeft(Tire backLeft) @safe nothrow {
59             	this.backLeft_ = backLeft;
60 
61             	return this;
62             }
63 
64             // ...
65 
66             @autowired // Automatically wire property using components from container identified by their types
67             Car backRight(Tire backRight) @safe nothrow {
68             	this.backRight_ = backRight;
69 
70             	return this;
71             }
72 
73             // ...
74 
75         }
76 
77         // ...
78     }
79 }

As seen above describing a component using annotation consists of annotating it with @component, optionally specyfing an identity using @qualifier, and annotating it with construction and configuration annotations such as:

  • @constructor (only on constructors) - annotates component with it's construction dependencies
  • @setter (only on setters) - annotates component with it's setter based dependencies
  • @autowired (not on constructors) - annotates component with it's setter based dependencies automatically
  • @autowired (on constructors) - annotates component with it's construction dependencies automatically
  • @callback (not on constructors) - annotates component with a custom function used to configure component
  • @callback (on constructors) - annotates component with a custom function used to create component
  • @contained (on component) - annotates component with information about container that manages it in a composite/joint container

Though annotations provide information about a component for framework, it does not automatically register them into container. To add annotated components to a container use scan family of functions. Example below shows how it is possible to register an entire module using just one line of code:

container.scan!(app); // load all annotated components from module "app"

Other forms of scan exists. Check api documentation to see alternatives of module based component registration if needed.

The result of running example, will yield into following output:

Uuh, what a nice car, Electric car with following specs:
Size:   Size(200, 150, 500)
Color:  Color(0, 255, 0)
Engine: app.ElectricEngine
Tire front left:        Tire(17 inch, 3 atm, divine tire)        located at memory 7FCC35376100
Tire front right:       Tire(17 inch, 3 atm, divine tire)        located at memory 7FCC35376140
Tire back left:         Tire(17 inch, 3 atm, divine tire)        located at memory 7FCC35376180
Tire back right:        Tire(17 inch, 3 atm, divine tire)        located at memory 7FCC353761C0

Check example below. Modify it, run it to understand annotation based configuration.

Members

Classes

Car
class Car

A class representing a car.

CarManufacturer
class CarManufacturer

A manufacturer of cars.

DieselEngine
class DieselEngine

A concrete implementation of Engine that uses diesel for propelling.

ElectricEngine
class ElectricEngine

A concrete implementation of Engine that uses electricity for propelling.

GasolineEngine
class GasolineEngine

A concrete implementation of Engine that uses gasoline for propelling.

ManufacturedCar
class ManufacturedCar
Undocumented in source.
Tire
class Tire

Tire, what it can represent else?

Functions

drive
void drive(Car car, string name)
Undocumented in source. Be warned that the author may not have intended to support it.
main
void main()
Undocumented in source. Be warned that the author may not have intended to support it.

Interfaces

Engine
interface Engine

Interface for engines.

Structs

Color
struct Color

A struct that should be managed by container.

Size
struct Size

Size of a car.

Meta

License

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:

The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Authors

aermicioi