Skip to content

Factory and Member Injector registries

Daniel Molinero edited this page Feb 1, 2019 · 17 revisions

Notice:

This only applies to TP 1.X. TP 2 does not use registries anymore.

This document only applies if an application uses disableReflection configuration. By default Toothpick uses reflection to retrieve factories and member injectors. But a more advanced configuration allows to gain more speed. See configurations for a detailed benchmark.


Both Factories and Member Injectors are generated by Toothpick annotation processors. Factories allow to create instances, whereas Member Injectors allow to assign @Inject annotated fields and call @Inject annotated methods.

FactoryRegistries and MemberInjectorRegistries allow Toothpick to retrieve the factory and member injector instances.

Setting up the registries

Toothpick generates the registries at the same time it generates the factories and member injectors. As a developer using Toothpick, you need to

  • configure the package into which the annotation processor will generate the registries for a given compilation unit (the application and each library);
  • inform the toothpick annotation processor of possible dependency of your compilation unit : toothpick will need to know where to find the registries for each of them.

Example : Simple application

Let's say we define a simple application that doesn't use any library using Toothpick:

// Simple application 
Application

In this case, the configuration of the registries will be as follow (for Android):

//configure a simple Android application without any dependency
//on a library using Toothpick.
android {
  ...
  defaultConfig {
    ...
    javaCompileOptions {
      annotationProcessorOptions {
        arguments = [ toothpick_registry_package_name : '<package>' ]
      }
    }
  }
}

dependencies {
    annotationProcessor 'com.github.stephanenicolas:toothpick-compiler:x.y.z'
    compile 'com.github.stephanenicolas:toothpick-runtime:x.y.z'
}

Toothpick only needs the annotation processor option toothpick_registry_package_name to point to the package where the registries for this application will be used.

Then, at runtime, we need to indicate to Toothpick where to find the registries for the application :

Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); // Production
FactoryRegistryLocator.setRootRegistry(new <package>.FactoryRegistry());
MemberInjectorRegistryLocator.setRootRegistry(new <package>.MemberInjectorRegistry());

where the package is the same package that was provided to the annotation processor.

Example : Application with 3 libraries

Now, let's take the example of an application that uses 3 libraries. All of them use Toothpick. The application uses directly lib 1 and lib 2. And lib 2, in turn, uses lib3. As we will see, Toothpick registries are also organized as a tree.

//Application using 3 libraries, all of them using Toothpick
Application
 |
 + --- Lib 1
 |
 \ -+- Lib 2
    |
    \--- Lib 3

Then the 4 compilation units (the application and the 3 libraries), will need to be configured as follow: In this case, the configuration of the registries will be as follow (for Android).

For lib3, which has no dependencies on any library using Toothpick:

//configure a library application without any dependency
//on a library using Toothpick.
android {
  ...
  defaultConfig {
    ...
    javaCompileOptions {
      annotationProcessorOptions {
        arguments = [ toothpick_registry_package_name : '<package lib3>' ]
      }
    }
  }
}

dependencies {
    annotationProcessor 'com.github.stephanenicolas:toothpick-compiler:x.y.z'
    compile 'com.github.stephanenicolas:toothpick-runtime:x.y.z'
}

The same would apply to lib1 has it doesn't depend on any library using Toothpick.

For lib2, which has one dependency on lib3:

//configure a library application without any dependency
//on a library using Toothpick.
android {
  ...
  defaultConfig {
    ...
    javaCompileOptions {
      annotationProcessorOptions {
        arguments = [ toothpick_registry_package_name : '<package lib2>',
                      toothpick_registry_children_package_names : "<package lib3>" ]
      }
    }
  }
}

dependencies {
    annotationProcessor 'com.github.stephanenicolas:toothpick-compiler:x.y.z'
    compile 'com.github.stephanenicolas:toothpick-runtime:x.y.z'
}

And finally, for the application itself, Toothpick annotation processors would need to be configured with:

//configure a library application without any dependency
//on a library using Toothpick.
android {
  ...
  defaultConfig {
    ...
    javaCompileOptions {
      annotationProcessorOptions {
        arguments = [ toothpick_registry_package_name : '<package app>',
                      toothpick_registry_children_package_names : "<package lib1>,<package lib2>" ] //not lib3
      }
    }
  }
}

dependencies {
    annotationProcessor 'com.github.stephanenicolas:toothpick-compiler:x.y.z'
    compile 'com.github.stephanenicolas:toothpick-runtime:x.y.z'
}

Then, at runtime, we need to indicate to Toothpick where to find the registries for the application :

Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); // Production
FactoryRegistryLocator.setRootRegistry(new <package app>.FactoryRegistry());
MemberInjectorRegistryLocator.setRootRegistry(new <package app>.MemberInjectorRegistry());

where the package is the same package that was provided to the annotation processor for the application.

Limitation of the approach

The only problem with the registries approach (beyond the extra configuration steps) is that every library using DI and that will be used by Toothpick needs to be compiled with Toothpick.

Links