JBoss.orgCommunity Documentation

Chapter 3. Dependency Injection

3.1. Container Wiring
3.2. Wiring server side components
3.3. Scopes
3.3.1. Dependent Scope
3.4. Built-in Extensions
3.4.1. Bus Services
3.4.2. Client Components
3.4.3. Lifecycle Tools
3.5. Client-Side Bean Manager
3.5.1. Looking up beans
3.5.2. Availability of beans
3.6. Alternatives and Mocks
3.6.1. Alternatives
3.6.2. Test Mocks
3.7. Bean Lifecycle
3.7.1. Destruction of Beans

The core Errai IOC module implements 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.

Classpath Scanning and ErraiApp.properties

Errai only scans the contents of classpath locations (JARs and directories) that have a file called ErraiApp.properties at their root. If dependency injection is not working for you, double-check that you have an ErraiApp.properties in every JAR and directory that contains classes Errai should know about.

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());
  }
}

In order to inject TimeService , you must annotate it with @ApplicationScoped or the Errai DI container will not acknowledge the type as a bean.



@ApplicationScoped
public class TimeService {
}

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.

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 and auto-discovered by the container.

A Provider is essentially a factory which produces type instances within in the container, and 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:

  • org.jboss.errai.ioc.client.api.builtin.MessageBusProvider : Makes an instance of MessageBus available for injection.

  • org.jboss.errai.ioc.client.api.builtin.RequestDispatchProvider : Makes an instance of the RequestDispatcher available for injection.

  • org.jboss.errai.ioc.client.api.builtin.ConsumerProvider : Makes event Consumer<?> objects available for injection.

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

TimeService.java



public interface TimeService {
  public String getTime();
}

TimeServiceProvider.java



@IOCProvider
@Singleton
public class TimeServiceProvider implements Provider<TimeService> {
  @Override
  public TimeService get() {
    return new TimeService() {
      public String getTime() {
        return "It's midnight somewhere!";
      }
    };
  }
}

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



Guice.createInjector(new AbstractModule() {
  public void configure() {
    bind(TimeService.class).toProvider(TimeServiceProvider.class);
  }
 }).getInstance(MyApp.class);

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.

Important

Top-level providers are treated as regular beans. And as such may inject dependencies – particularly from other top-level providers – as necessary.

By default, Errai uses Google Guice to wire server-side components. When deploying services on the server-side, it is currently possible to obtain references to the MessageBus , RequestDispatcher , the ErraiServiceConfigurator , and ErraiService by declaring them as injection dependencies in Service classes, extension components, and session providers.

Alternatively, supports CDI based wiring of server-side components. See the chapter on Errai CDI for more information.

Out of the box, the IOC container supports three bean scopes, @Dependent , @Singleton and @EntryPoint . The singleton and entry-point scopes are roughly the same semantics.

In Errai IOC, all client types are valid bean types if they are default constructable or can have construction dependencies satisfied. These unqualified beans belong to the dependent pseudo-scope. See: Dependent Psuedo-Scope from CDI Documentation

Additionally, beans may be qualified as @ApplicationScoped , @Singleton or @EntryPoint . Although @ApplicationScoped and @Singleton are supported for completeness and conformance, within the client they effectively result in behavior that is identical.



Availability of dependent beans in the client-side BeanManager

As is mentioned in the bean manager documentation , only beans that are explicitly scoped will be made available to the bean manager for lookup. So while it is not necessary for regular injection, you must annotate your dependent scoped beans with @Dependent if you wish to dynamically lookup these beans at runtime.

As Errai IOC provides a container-based approach to client development, support for Errai services are exposed to the container so they may be injected and used throughout your application where appropriate. This section covers those services.

The IOC container, by default, provides a set of default injectable bean types. They range from basic services, to injectable proxies for RPC. This section covers the facilities available out-of-the-box.

A problem commonly associated with building large applications in the browser is ensuring that things happen in the proper order when code starts executing. Errai IOC provides you tools which permit you to ensure things happen before initialization, and forcing things to happen after initialization of all of the Errai services.

It may be necessary at times to obtain instances of beans managed by Errai IOC from outside the container managed scope or creating a hard dependency from your bean. Errai IOC provides a simple client-side bean manager for handling these scenarios: org.jboss.errai.ioc.client.container.IOCBeanManager .

As you might expect, you can inject the bean manager into any of your managed beans.


If you need to access the bean manager outside a managed bean, such as in a unit test, you can access it by calling org.jboss.errai.ioc.client.container.IOC.getBeanManager()

It may be desirable to have multiple matching dependencies for a given injection point with the ability to specify which implementation to use at runtime. For instance, you may have different versions of your application which target different browsers or capabilities of the browser. Using alternatives allows you to share common interfaces among your beans, while still using dependency injection, by exporting consideration of what implementation to use to the container's configuration.

Consider the following example:

and

In our controller logic we in turn inject the View interface:

This code is unaware of the implementation of View , which maintains good separation of concerns. However, this of course creates an ambiguous dependency on the View interface as it has two matching subtypes in this case. Thus, we must configure the container to specify which alternative to use. Also note, that the beans in both cases have been annotated with javax.enterprise.inject.Alternative .

In your ErraiApp.properties for the module, you can simply specify which active alternative should be used:

You can specify multiple alternative classes by white space separating them:

You can only have one enabled alternative for a matching set of alternatives, otherwise you will get ambiguous resolution errors from the container.

Similar to alternatives, but specifically designed for testing scenarios, you can replace beans with mocks at runtime for the purposes of running unit tests. This is accomplished simply by annotating a bean with the org.jboss.errai.ioc.client.api.TestMock annotation. Doing so will prioritize consideration of the bean over any other matching beans while running unit tests.

Consider the following:

You can specify a mock implementation of this class by implementing its common parent type ( UserManagement ) and annotating that class with the @TestMock annotation inside your test package like so:

In this case, the container will replace the UserManagementImpl with the MockUserManagementImpl automatically when running the unit tests.

The @TestMock annotation can also be used to specify alternative providers during test execution. For example, it can be used to mock a Caller<T> . Callers are used to invoke RPC or JAX-RS endpoints. During tests you might want to replace theses callers with mock implementations. For details on providers see Section 3.1, “Container Wiring” .



@TestMock @IOCProvider
public class MockedHappyServiceCallerProvider implements ContextualTypeProvider<Caller<HappyService>> {
 
  @Override
  public Caller<HappyService> provide(Class<?>[] typeargs, Annotation[] qualifiers) {
    return new Caller<HappyService>() {
      ...
    }
}

All beans managed by the Errai IOC container support the @PostConstruct and @PreDestroy annotations.

Beans which have methods annotated with @PostConstruct are guaranteed to have those methods called before the bean is put into service, and only after all dependencies within its graph has been satisfied.

Beans are also guaranteed to have their @PreDestroy annotated methods called before they are destroyed by the bean manager.

Beans under management of Errai IOC, of any scope, can be explicitly destroyed through the client bean manager. Destruction of a managed bean is accomplished by passing a reference to the destroyBean() method of the bean manager.


When the bean manager "destroys" the bean, any pre-destroy methods the bean declares are called, it is taken out of service and no longer tracked by the bean manager. If there are references on the bean by other objects, the bean will continue to be accessible to those objects.

Important

Container managed resources that are dependent on the bean such as bus service endpoints or CDI event observers will also be automatically destroyed when the bean is destroyed.

Another important consideration is the rule, "all beans created together are destroyed together." Consider the following example:



In this example we pass the instance of AnotherBean, created as a dependency of SimpleBean, to the bean manager for destruction. Because this bean was created at the same time as its parent, its destruction will also result in the destruction of SimpleBean ; thus, this action will result in the @PreDestroy cleanUp() method of SimpleBean being invoked.