Prefer the use of @Inject in examples, docs and tests

This commit is contained in:
Mike Bierlee 2023-03-07 03:29:54 +03:00
parent 3fa4e15d6f
commit a129e6c3f1
12 changed files with 86 additions and 84 deletions

View file

@ -51,7 +51,7 @@ class RelationalDatabase : Database {
}
class DataWriter {
@Autowire
@Inject
private Database database; // Automatically injected when class is resolved
}

View file

@ -89,17 +89,17 @@ dependencies.register!ExampleClass.initializedBy({
## Automatic Injection
The real value of any dependency injection framework comes from its ability to automatically inject dependencies. Poodinis supports automatic injection either through autowiring members annotated with the `@Autowire` UDA or through constructor injection.
The real value of any dependency injection framework comes from its ability to automatically inject dependencies. Poodinis supports automatic injection either through autowiring members annotated with the `@Inject` attribute or through constructor injection.
### UDA-based Autowiring
### Attribute-based Injection
UDA-based autowiring can be achieved by annotating members of a class with the `@Autowire` UDA:
Attribute-based injection can be achieved by annotating members of a class with the `@Inject` attribute:
```d
class ExampleClassA {}
class ExampleClassB {
@Autowire
@Inject
private ExampleClassA dependency;
}
@ -109,9 +109,9 @@ dependencies.autowire(exampleInstance);
assert(exampleInstance.dependency !is null);
```
It is possible to autowire public as well as protected and private members.
It is possible to inject public as well as protected and private members.
Dependencies are automatically autowired when a class is resolved. So when you resolve `ExampleClassB`, its member `dependency` is automatically autowired:
Dependencies are automatically injected when a class is resolved. So when you resolve `ExampleClassB`, its member `dependency` is automatically injected:
```d
dependencies.register!ExampleClassA;
@ -120,15 +120,15 @@ auto instance = dependencies.resolve!ExampleClassB;
assert(instance.dependency !is null);
```
If an interface is to be autowired, you must register a concrete class by interface. A class registered only by concrete type can only be injected into members of that type, not its supertypes.
If an interface is to be injected, you must register a concrete class by interface. A class registered only by concrete type can only be injected into members of that type, not its supertypes.
Using the UDA `OptionalDependency` you can mark an autowired member as being optional. When a member is optional, no ResolveException will be thrown when
Using the attribute `@OptionalDependency` you can mark an injected member as being optional. When a member is optional, no ResolveException will be thrown when
the type of the member is not registered and `ResolveOption.registerBeforeResolving` is not set on the container. The member will remain null or an empty array in
case of array dependencies.
```d
class ExampleClass {
@Autowire
@Inject
@OptionalDependency
private AnotherExampleClass dependency;
}
@ -196,13 +196,13 @@ You can only register one value injector per type, a resolve exception will be t
Besides injecting primitive types, it is also possible to inject structs. While it is possible to inject class instances this way, this mechanism isn't really meant for that.
Value injectors will also be autowired before being used. Value injectors will even be value injected themselves, even if they will use themselves to do so. Dependencies of value injectors will also be value injected. Be extremely careful with relying on injected values within value injectors though, you might easily create a stack overflow or a chicken-egg situation.
Value injectors will also be injected before being used. Value injectors will even be value injected themselves, even if they will use themselves to do so. Dependencies of value injectors will also be value injected. Be extremely careful with relying on injected values within value injectors though, you might easily create a stack overflow or a chicken-egg situation.
Poodinis doesn't come with any value injector implementations. In the [README.md](README.md) you will find a list of projects which use different libraries as value sources.
## Circular Dependencies
Poodinis can autowire circular dependencies when they are registered with `singleInstance` or `existingInstance` registration scopes. Circular dependencies in registrations with `newInstance` scopes will not be autowired, as this would cause an endless loop. Circular dependencies are only supported when autowiring members through the `@Autowire` UDA; circular dependencies in constructors are not supported and will result in an `InstanceCreationException`.
Poodinis can inject circular dependencies when they are registered with `singleInstance` or `existingInstance` registration scopes. Circular dependencies in registrations with `newInstance` scopes will not be injected, as this would cause an endless loop. Circular dependencies are only supported when autowiring members through the `@Inject` attribute; circular dependencies in constructors are not supported and will result in an `InstanceCreationException`.
## Registering and Resolving Using Qualifiers
@ -215,11 +215,11 @@ dependencies.register!(Color, Red);
auto blueInstance = dependencies.resolve!(Color, Blue);
```
If you want to autowire a type registered to multiple concrete types, specify a qualified type as template argument:
If you want to inject a type registered to multiple concrete types, specify a qualified type as template argument:
```d
class BluePaint {
@Autowire!Blue
@Inject!Blue
private Color color;
}
```
@ -228,13 +228,13 @@ If you registered multiple concrete types to the same supertype and you do not r
## Autowiring All Registered Instances to an Array
If you have registered multiple concrete types to a super type, you can autowire them all to an array, in which case you can easily operate on them all:
If you have registered multiple concrete types to a super type, you can inject them all to an array, in which case you can easily operate on them all:
```d
// Color is an interface, Blue and Red are classes implementing that interface
class ColorMixer {
@Autowire
@Inject
private Color[] colors;
}
@ -272,7 +272,7 @@ In the override `registerDependencies()` you can register all dependencies which
This override is optional. You can still register simple dependencies outside of the context (or in another context).
Complex dependencies are registered through member methods of the context. These member methods serve as factory methods which will be called when a dependency is resolved.
They are annotated with the `@Component` UDA to let the container know that these methods should be registered as dependencies. The type of the registration is the same as the return type of the method.
They are annotated with the `@Component` attribute to let the container know that these methods should be registered as dependencies. The type of the registration is the same as the return type of the method.
Factory methods are useful when you have to deal with dependencies which require constructor arguments or elaborate set-up after instantiation.
@ -282,21 +282,21 @@ Application contexts have to be registered with a dependency container. They are
container.registerContext!Context;
```
All registered dependencies can now be resolved by the same dependency container. Registering a context will also register it as a dependency, meaning you can autowire the application context in other classes.
All registered dependencies can now be resolved by the same dependency container. Registering a context will also register it as a dependency, meaning you can inject the application context in other classes.
You can register as many types of application contexts as you like.
### Autowiring Application Contexts
Application contexts can make use of autowired dependencies like any other dependency. When registering an application context, all its components are registered first after which the application context is autowired.
This means that after the registration of an application context some dependencies will already be resolved and instantiated. The following example illustrates how autowired members can be used in a context:
Application contexts can make use of injected dependencies like any other dependency. When registering an application context, all its components are registered first after which the application context is injected.
This means that after the registration of an application context some dependencies will already be resolved and instantiated. The following example illustrates how injected members can be used in a context:
```d
class Context : ApplicationContext {
@Autowire
@Inject
private SomeClass someClass;
@Autowire
@Inject
private SomeOtherClass someOtherClass;
public override void registerDependencies(shared(DependencyContainer) container) {
@ -310,14 +310,14 @@ class Context : ApplicationContext {
}
```
As you can see, autowired dependencies can be used within factory methods. When `SomeLibraryClass` is resolved, it will be created with a resolved instance of `SomeClass` and `SomeOtherClass`. As shown, autowired dependencies can be registered within the same
application context, but don't neccesarily have to be. You can even autowire dependencies which are created within a factory method within the same application context.
As you can see, injected dependencies can be used within factory methods. When `SomeLibraryClass` is resolved, it will be created with a resolved instance of `SomeClass` and `SomeOtherClass`. As shown, injected dependencies can be registered within the same
application context, but don't neccesarily have to be. You can even inject dependencies which are created within a factory method within the same application context.
Application contexts are directly autowired after they have been registered. This means that all autowired dependencies which are not registered in the application context itself need to be registered before registering the application context.
Application contexts are directly injected after they have been registered. This means that all injected dependencies which are not registered in the application context itself need to be registered before registering the application context.
### Controlling Component Registration
You can further influence how components are registered and created with additional UDAs:
You can further influence how components are registered and created with additional attributes:
```d
class Context : ApplicationContext {
@ -350,13 +350,13 @@ Please note that setting options will unset previously set options; the options
## Post-Constructors and Pre-Destructors
Using the `@PostConstruct` and `@PreDestroy` UDAs you can let the container call public methods in your class right after the container constructed it or when it loses its registration for your class. The pre-constructor is called right after the container has created a new instance of your class and has autowired its members. The post-construtor is called when `removeRegistration` or `clearAllRegistrations` is called, or when the container's destructor is called. A post-constructor or pre-destructor must have the signature `void(void)`.
Using the `@PostConstruct` and `@PreDestroy` attributes you can let the container call public methods in your class right after the container constructed it or when it loses its registration for your class. The pre-constructor is called right after the container has created a new instance of your class and has injected its members. The post-construtor is called when `removeRegistration` or `clearAllRegistrations` is called, or when the container's destructor is called. A post-constructor or pre-destructor must have the signature `void(void)`.
```d
class MyFineClass {
@PostConstruct
void postConstructor() {
// Is called right after MyFineClass is created and autowired
// Is called right after MyFineClass is created and injected
}
@PreDestroy

View file

@ -32,11 +32,11 @@ class SuperSecurityDevice {
}
class SecurityManager {
@Autowire private SuperSecurityDevice levelOneSecurity;
@Inject private SuperSecurityDevice levelOneSecurity;
@Autowire @AssignNewInstance private SuperSecurityDevice levelTwoSecurity;
@Inject @AssignNewInstance private SuperSecurityDevice levelTwoSecurity;
@Autowire @OptionalDependency private SecurityAuditor auditor;
@Inject @OptionalDependency private SecurityAuditor auditor;
public void doAudit() {
if (auditor !is null) {

View file

@ -10,7 +10,7 @@ import poodinis;
import std.stdio;
class TownSquare {
@Autowire private MarketStall marketStall;
@Inject private MarketStall marketStall;
public void makeSound() {
marketStall.announceGoodsForSale();
@ -40,7 +40,7 @@ class MarketStall {
}
class ExampleApplicationContext : ApplicationContext {
@Autowire private Goods goods;
@Inject private Goods goods;
public override void registerDependencies(shared(DependencyContainer) container) {
container.register!(Goods, Fish);

View file

@ -32,7 +32,7 @@ class CardboardBoxPie : Pie {
}
class PieEater {
@Autowire private Pie[] pies;
@Inject private Pie[] pies;
public void eatThemAll() {
foreach (pie; pies) {

View file

@ -20,7 +20,7 @@ class ADependency {
}
class AClass {
@Autowire public ADependency dependency; // Dependencies are autowired before the post-constructor is called.
@Inject public ADependency dependency; // Dependencies are autowired before the post-constructor is called.
@PostConstruct public void postConstructor() {
writeln("The class is created.");

View file

@ -28,9 +28,9 @@ class ElectricEngine : Engine {
class HybridCar {
alias KilometersPerHour = int;
@Autowire!FuelEngine private Engine fuelEngine;
@Inject!FuelEngine private Engine fuelEngine;
@Autowire!ElectricEngine private Engine electricEngine;
@Inject!ElectricEngine private Engine electricEngine;
public void moveAtSpeed(KilometersPerHour speed) {
if (speed <= 45) {

View file

@ -22,7 +22,7 @@ class RelationalDatabase : Database {
}
class DataWriter {
@Autowire private Database database; // Automatically injected when class is resolved
@Inject private Database database; // Automatically injected when class is resolved
}
void main() {

View file

@ -15,12 +15,12 @@ interface InstrumentPlayer {
class ViolinPlayer : InstrumentPlayer {
// Autowired concrete types can be registered on resolve
@Autowire private Violin violin;
@Inject private Violin violin;
}
class Orchestra {
// Autowired non-concrete types can be registered on resolved, given they have a qualifier.
@Autowire!ViolinPlayer private InstrumentPlayer violinPlayer;
@Inject!ViolinPlayer private InstrumentPlayer violinPlayer;
}
void main() {

View file

@ -44,6 +44,8 @@ private struct UseMemberType {
* of a concrete class is used to autowire members declared by supertype. If no qualifier is supplied, the type
* of the member is used as qualifier.
*
* Note: @Autowire is considered legacy, but not deprecated. Using @Inject is preferred.
*
* Examples:
* Annotate member of class to be autowired:
* ---

View file

@ -649,13 +649,13 @@ version (unittest) {
assert(instance.lala(77) == 77);
}
// Test autowiring using @Inject attribute
// Test autowiring using @Autowire attribute
unittest {
auto container = new shared DependencyContainer();
container.register!ComponentA;
container.register!WithInjectAttribute;
container.register!WithAutowireAttribute;
auto instance = container.resolve!WithInjectAttribute;
auto instance = container.resolve!WithAutowireAttribute;
assert(instance.componentA is container.resolve!ComponentA);
}
}

View file

@ -15,7 +15,7 @@ version (unittest) {
}
class ComponentB {
public @Autowire ComponentA componentA;
public @Inject ComponentA componentA;
}
interface InterfaceA {
@ -25,8 +25,8 @@ version (unittest) {
}
class ComponentD {
public @Autowire InterfaceA componentC = null;
private @Autowire InterfaceA _privateComponentC = null;
public @Inject InterfaceA componentC = null;
private @Inject InterfaceA _privateComponentC = null;
public InterfaceA privateComponentC() {
return _privateComponentC;
@ -43,7 +43,7 @@ version (unittest) {
class ComponentDeclarationCocktail {
alias noomer = int;
@Autowire public ComponentA componentA;
@Inject public ComponentA componentA;
public void doesNothing() {
}
@ -59,36 +59,36 @@ version (unittest) {
}
class MonkeyShine {
@Autowire!ComponentX public InterfaceA component;
@Inject!ComponentX public InterfaceA component;
}
class BootstrapBootstrap {
@Autowire!ComponentX public InterfaceA componentX;
@Inject!ComponentX public InterfaceA componentX;
@Autowire!ComponentC public InterfaceA componentC;
@Inject!ComponentC public InterfaceA componentC;
}
class LordOfTheComponents {
@Autowire public InterfaceA[] components;
@Inject public InterfaceA[] components;
}
class ComponentCharlie {
@Autowire @AssignNewInstance public ComponentA componentA;
@Inject @AssignNewInstance public ComponentA componentA;
}
class OuttaTime {
@Autowire @OptionalDependency public InterfaceA interfaceA;
@Inject @OptionalDependency public InterfaceA interfaceA;
@Autowire @OptionalDependency public ComponentA componentA;
@Inject @OptionalDependency public ComponentA componentA;
@Autowire @OptionalDependency public ComponentC[] componentCs;
@Inject @OptionalDependency public ComponentC[] componentCs;
}
class ValuedClass {
@Value("values.int")
public int intValue;
@Autowire public ComponentA unrelated;
@Inject public ComponentA unrelated;
}
class TestInjector : ValueInjector!int {
@ -105,7 +105,7 @@ version (unittest) {
}
class TestClassDeux : TestInterface {
@Autowire public UnrelatedClass unrelated;
@Inject public UnrelatedClass unrelated;
}
class UnrelatedClass {
@ -121,46 +121,46 @@ version (unittest) {
}
class ComponentClass {
@Autowire public AutowiredClass autowiredClass;
@Inject public AutowiredClass autowiredClass;
}
class ComponentCat {
@Autowire public ComponentMouse mouse;
@Inject public ComponentMouse mouse;
}
class ComponentMouse {
@Autowire public ComponentCat cat;
@Inject public ComponentCat cat;
}
class Eenie {
@Autowire public Meenie meenie;
@Inject public Meenie meenie;
}
class Meenie {
@Autowire public Moe moe;
@Inject public Moe moe;
}
class Moe {
@Autowire public Eenie eenie;
@Inject public Eenie eenie;
}
class Ittie {
@Autowire public Bittie bittie;
@Inject public Bittie bittie;
}
class Bittie {
@Autowire public Bunena banana;
@Inject public Bunena banana;
}
class Bunena {
@Autowire public Bittie bittie;
@Inject public Bittie bittie;
}
interface SuperInterface {
}
class SuperImplementation : SuperInterface {
@Autowire public Bunena banana;
@Inject public Bunena banana;
}
interface Color {
@ -173,26 +173,26 @@ version (unittest) {
}
class Spiders {
@Autowire public TestInterface testMember;
@Inject public TestInterface testMember;
}
class Recursive {
@Autowire public Recursive recursive;
@Inject public Recursive recursive;
}
class Moolah {
}
class Wants {
@Autowire public Moolah moolah;
@Inject public Moolah moolah;
}
class John {
@Autowire public Wants wants;
@Inject public Wants wants;
}
class Cocktail {
@Autowire public Moolah moolah;
@Inject public Moolah moolah;
public Red red;
@ -263,7 +263,7 @@ version (unittest) {
}
class PostConstructWithAutowiring {
@Autowire private PostConstructionDependency dependency;
@Inject private PostConstructionDependency dependency;
@Value("")
private int theNumber = 1;
@ -359,9 +359,9 @@ version (unittest) {
class ComplexAutowiredTestContext : ApplicationContext {
@Autowire private Apple apple;
@Inject private Apple apple;
@Autowire protected ClassWrapper classWrapper;
@Inject protected ClassWrapper classWrapper;
public override void registerDependencies(shared(DependencyContainer) container) {
container.register!Apple;
@ -379,7 +379,7 @@ version (unittest) {
class AutowiredTestContext : ApplicationContext {
@Autowire private Apple apple;
@Inject private Apple apple;
@Component public ClassWrapper wrapper() {
return new ClassWrapper(apple);
@ -561,7 +561,7 @@ version (unittest) {
}
class DependencyInjectedIntInjector : ValueInjector!int {
@Autowire public Dependency dependency;
@Inject public Dependency dependency;
public override int get(string key) {
return 2345;
@ -569,7 +569,7 @@ version (unittest) {
}
class CircularIntInjector : ValueInjector!int {
@Autowire public ValueInjector!int dependency;
@Inject public ValueInjector!int dependency;
private int count = 0;
@ -596,7 +596,7 @@ version (unittest) {
}
class DependencyValueInjectedIntInjector : ValueInjector!int {
@Autowire public ConfigWithDefaults config;
@Inject public ConfigWithDefaults config;
public override int get(string key) {
if (key == "conf.missing") {
@ -608,7 +608,7 @@ version (unittest) {
}
class TemplatedComponent(T) {
@Autowire T instance;
@Inject T instance;
}
class CircularTemplateComponentA : TemplatedComponent!CircularTemplateComponentB {
@ -640,18 +640,18 @@ version (unittest) {
}
class AutowiredMethod {
@Autowire
@Inject
public int lala() {
return 42;
}
@Autowire
@Inject
public int lala(int valla) {
return valla;
}
}
class WithInjectAttribute {
public @Inject ComponentA componentA;
class WithAutowireAttribute {
public @Autowire ComponentA componentA;
}
}