Binding transformations
In this tutorial, we will transform bindings declared in a separate standalone module. We will intercept a dependency exported in another module and transform it so that it adds some basic logging before method execution and after method finishes.
Example Launcher
First, we will create a new Launcher by extending the Launcher
class.
public class BindingTransformationExample extends Launcher {
...
}
Then let's define the Person
interface with a single method void greet()
.
public interface Person {
void greet();
}
And inject an instance of a Person
class into the application launcher by adding a person
field annotated with the @Inject
annotation.
@Inject
Person person;
Our application launcher overrides Launcher#run
method just to call person.greet()
method.
@Override
protected void run() {
person.greet();
}
Person module
An application launcher would use 2 modules to inject a Person person
dependency.
@Override
protected Module getModule() {
return Modules.combine(
new PersonModule(),
new PersonTransformModule()
);
}
The first one (PersonModule
) is a simple AbstractModule
that provides a single dependency for a Person
class.
public static class PersonModule extends AbstractModule {
@Provides
Person greeter() {
return () -> System.out.println("Hello!");
}
}
A provided Person
simply prints "Hello!"
when greet()
method is called.
Person transformation module
The PersonTransformModule
is a module that intercepts the provided Person
class and adds logging to the greet()
method calls.
public static class PersonTransformModule extends AbstractModule {
@Override
protected void configure() {
transform(Person.class, (bindings, scope, key, binding) ->
binding.mapInstance(person ->
() -> {
System.out.println("Start of greeting");
person.greet();
System.out.println("End of greeting");
}
));
}
}
The module does not export any dependency using the @Provides
annotation. Instead it overrides AbstractModule#configure
method only to call the transform(...)
method.
Let's take a closer look at the transform(...)
call. It takes 2 arguments:
Class
- the class of a binding to be transformed (it can be changed to aKeyPattern
to transform all bindings matched by a key pattern)BindingTransformer<T>
- a transformer which is itself a functional interfaces that accepts bindings, scope, current key and binding and returns a new binding (or the same binding if no transformation occurred)
We call Binding#mapInstance
method on the received binding and specify how the Person
instance should be transformed.
Here we return a new instance of the Person
class, which adds some System.out
logs before and after calling person.greet()
on an original person instance.
Launching the example
To launch the example, we need to define the main
method that simply creates a new instance of our application launcher and passes the application arguments to the Launcher#launch
method.
public static void main(String[] args) throws Exception {
BindingTransformationExample launcher = new BindingTransformationExample();
launcher.launch(args);
}
When launching the application it should print to stdout
:
Start of greeting
Hello!
End of greeting
You can find example sources on Github