JBoss.orgCommunity Documentation
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()); } }
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 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:
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.
Top-level providers are treated as regular beans. And as such may inject dependencies – particularly from other top-level providers – as necessary.
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:
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.
Top-level providers are treated as regular beans. And as such may inject dependencies – particularly from other top-level providers – as necessary.
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:
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.
Top-level providers are treated as regular beans. And as such may inject dependencies – particularly from other top-level providers – as necessary.
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()); } }
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.