Generating bindings
In this tutorial we will generate a binding for an arbitrary type Supplier
.
Supplier Generator Module
We define a standalone module responsible solely for defining the Supplier<T>
generator.
public static final class SupplierGeneratorModule extends AbstractModule {
@Override
protected void configure() {
generate(Supplier.class, (bindings, scope, key) -> {
Binding<?> binding = bindings.get(key.getTypeParameter(0));
return binding != null ?
binding.mapInstance(instance -> () -> instance) :
Binding.toInstance(() -> null);
});
}
}
If there is a known binding for type T
, as in Supplier<T>
, we generate a binding for that instance's Supplier
.
Otherwise, we generate a binding for a Supplier
that always supplies null
.
Running the example
We need to create a new Injector
and install the SupplierGeneratorModule
. We also need to bind a String
to a "Hello, World"
value.
To let the Injector
know that we may be requesting instances of Supplier<String>
and Supplier<Integer>
, we also need to bind the corresponding keys.
Injector injector = Injector.of(ModuleBuilder.create()
.install(new SupplierGeneratorModule())
.bind(String.class).toInstance("Hello, World")
.bind(new Key<Supplier<String>>() {})
.bind(new Key<Supplier<Integer>>() {})
.build());
Supplier<String> stringSupplier = injector.getInstance(new Key<>() {});
System.out.println(stringSupplier.get()); // "Hello, World"
Supplier<Integer> integerSupplier = injector.getInstance(new Key<>() {});
System.out.println(integerSupplier.get()); // "null"
Then we receive instances of Supplier<String>
and Supplier<Integer>
from the Injector
.
- When we call
stringSupplier.get()
we receive a"Hello, World"
string, because the binding forString
was manually provided. - When we call
integerSupplier.get()
we receive anull
, because the binding forInteger
was never provided.
You can find example sources on GitHub
Generating bindings using @Provides
methods
In the example above, we defined a binding generator in SupplierGeneratorModule
using the AbstractModule#generate
method inside
the configure
method.
Alternatively, you can define binding generators using methods annotated with @Provides
annotation. We will use a special
OptionalDependency
class as a dependency, which lets us know if there is a provided
binding for some type.
This is what a SupplierGeneratorModule
might look like if we define a Supplier
binding generator using @Provides
annotation:
public static final class SupplierGeneratorModule extends AbstractModule {
@Provides
<T> Supplier<T> supplier(OptionalDependency<T> optionalDependency) {
if (optionalDependency.isPresent()) {
return optionalDependency::get;
} else {
return () -> null;
}
}
}