JBoss.orgCommunity Documentation

Chapter 21. Errai IOC

21.1. Dependency Injection
21.2. Container Wiring
21.2.1. level Providers
21.3. Container Wiring
21.3.1. level Providers
21.3.2. level Providers
21.4. Dependency Injection

The Errai IOC (Inversion-of-Control) module is a central feature of the Errai Framework, providing client-side service location, component lifecycle, and injection services. The framework is a modular and extensible system for building reusable client-side components.

The core Errai IOC module implements a subset of the JSR-330 Dependency Injection specification for in-client component wiring.

Dependency injection (DI) allows for cleaner and more modular code, by permitting the implementation of decoupled and type-safe components. By using DI, components do not need to be aware of the implementation of provided services. Instead, they merely declare a contract with the container, which in turn provides instances of the services that component depends on.

A simple example:

public class MyLittleClass {
  private final TimeService timeService;

  @Inject
  public MyLittleClass(TimeService timeService) {
    this.timeService = timeService;
  }

  public void printTime() {
    System.out.println(this.timeService.getTime());
  }
}

In this example, we create a simple class which declares a dependency using @Inject for the interface TimeService . In this particular case, we use constructor injection to establish the contract between the container and the component. We can similarly use field injection to the same effect:

public class MyLittleClass {
  @Inject
  private TimeService timeService;

  public void printTime() {
    System.out.println(this.timeService.getTime());
  }
}

Best Practices

Although field injection results in less code, a major disadvantage is that you cannot create immutable classes using the pattern, since the container must first call the default, no argument constructor, and then iterate through its injection tasks, which leaves the potential – albeit remote – that the object could be left in an partially or improperly initialized state. The advantage of constructor injection is that fields can be immutable (final), and invariance rules applied at construction time, leading to earlier failures, and the guarantee of consistent state.

@Inject

In contrast to Gin , the Errai IOC container does not provide a programmatic way of creating and configuring injectors. Instead, container-level binding rules are defined by implementing a Provider , which is scanned for an auto-discovered by the container.

A Provider is essentially a factory which produces dependent types in the container, which defers instantiation responsibility for the provided type to the provider implementation. Top-level providers use the standard javax.inject.Provider<T> interface.

Types made available as top-level providers will be available for injection in any managed component within the container.

Out of the box, Errai IOC implements three default top-level providers:

Implementing a Provider is relatively straight-forward. Consider the following two classes:

TimeService.java

TimeServiceProvider.java

If you are familiar with Guice, this is semantically identical to configuring an injector like so:

As shown in the above example code, the annotation @IOCProvider is used to denote top-level providers.

The classpath will be searched for all annotated providers at compile time.

In contrast to Gin , the Errai IOC container does not provide a programmatic way of creating and configuring injectors. Instead, container-level binding rules are defined by implementing a Provider , which is scanned for an auto-discovered by the container.

A Provider is essentially a factory which produces dependent types in the container, which defers instantiation responsibility for the provided type to the provider implementation. Top-level providers use the standard javax.inject.Provider<T> interface.

Types made available as top-level providers will be available for injection in any managed component within the container.

Out of the box, Errai IOC implements three default top-level providers:

Implementing a Provider is relatively straight-forward. Consider the following two classes:

TimeService.java

TimeServiceProvider.java

If you are familiar with Guice, this is semantically identical to configuring an injector like so:

As shown in the above example code, the annotation @IOCProvider is used to denote top-level providers.

The classpath will be searched for all annotated providers at compile time.

A Provider is essentially a factory which produces dependent types in the container, which defers instantiation responsibility for the provided type to the provider implementation. Top-level providers use the standard javax.inject.Provider<T> interface.

Types made available as top-level providers will be available for injection in any managed component within the container.

Out of the box, Errai IOC implements three default top-level providers:

Implementing a Provider is relatively straight-forward. Consider the following two classes:

TimeService.java

TimeServiceProvider.java

If you are familiar with Guice, this is semantically identical to configuring an injector like so:

As shown in the above example code, the annotation @IOCProvider is used to denote top-level providers.

The classpath will be searched for all annotated providers at compile time.

The core Errai IOC module implements a subset of the JSR-330 Dependency Injection specification for in-client component wiring.

Dependency injection (DI) allows for cleaner and more modular code, by permitting the implementation of decoupled and type-safe components. By using DI, components do not need to be aware of the implementation of provided services. Instead, they merely declare a contract with the container, which in turn provides instances of the services that component depends on.

A simple example:

public class MyLittleClass {
  private final TimeService timeService;

  @Inject
  public MyLittleClass(TimeService timeService) {
    this.timeService = timeService;
  }

  public void printTime() {
    System.out.println(this.timeService.getTime());
  }
}

In this example, we create a simple class which declares a dependency using @Inject for the interface TimeService . In this particular case, we use constructor injection to establish the contract between the container and the component. We can similarly use field injection to the same effect:

public class MyLittleClass {
  @Inject
  private TimeService timeService;

  public void printTime() {
    System.out.println(this.timeService.getTime());
  }
}

Best Practices

Although field injection results in less code, a major disadvantage is that you cannot create immutable classes using the pattern, since the container must first call the default, no argument constructor, and then iterate through its injection tasks, which leaves the potential – albeit remote – that the object could be left in an partially or improperly initialized state. The advantage of constructor injection is that fields can be immutable (final), and invariance rules applied at construction time, leading to earlier failures, and the guarantee of consistent state.

@Inject