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 forStringwas manually provided. - When we call
integerSupplier.get()we receive anull, because the binding forIntegerwas 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;
}
}
}