Skip to main content

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 executing the method and after the method finishes.

Example Launcher#

First, we will create a new Launcher by extending a Launcher class.

public class BindingTransformationExample extends Launcher {    ...}

Then let's define a 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 @Inject annotation.

@InjectPerson person;

Our application launcher overrides Launcher#run method just to call person.greet() method.

@Overrideprotected void run() {  person.greet();}

Person module#

An application launcher would use 2 modules to inject a Person person dependency.

@Overrideprotected 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#

A PersonTransformModule is a module that would intercept a provided Person class and add logging to 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 @Provides annotation. Instead it overrides AbstractModule#configure method just to call transform(...) method. Let's take a closer look at transform(...) call. It takes 2 arguments:

  • Class - a class of a binding which will be transformed (this can be changed to a KeyPattern to transform all bindings matched by a key pattern.
  • BindingTransformer<T> - a transformer which is itself a functional interfaces that takes bindings, scope, current key and binding and returns a new binding (or the same binding if no transformation happened)

We call Binding#mapInstance method on a a received binding and specify how an instance of a Person should be transformed. Here, we return a new instance of Person class that adds some System.out logging 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 which would simply create a new instance of our application launcher and pass application arguments to 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 greetingHello!End of greeting

You can find example sources on Github