Creating extensions

Generating modules and entry points

Hilt is particularly well-suited for extensions or libraries that want to integrate with Hilt due to the standard components and the way modules and entry points are picked up from the classpath.

However, extensions that generate an @InstallIn module or entry point will need to add some extra information to the generated classes in order for them to be picked up by Hilt correctly.

@GeneratesRootInput

Because Hilt picks up modules and entry points from the classpath implicitly, Hilt needs extra information to know if it needs to wait for your extension to generate code before it tries to generate the Dagger components. This is done by annotating your annotation class that triggers your code generation with @GeneratesRootInput.

For example, if an extension generated a module every time someone used a @GenerateMyModule annotation, @GenerateMyModule would need to be annotated like so:

Java
Kotlin
@GeneratesRootInput
public @interface GenerateMyModule {}
@GeneratesRootInput
annotation class GenerateMyModule {}

Note that if not annotated, Hilt is not necessarily guaranteed to miss your modules because it may still pick them up if waiting on something else to be generated. This is of course unreliable.

@OriginatingElement

As described in the testing page, nested modules in tests are isolated to the enclosing test. Generated modules for a test, however, cannot be generated as a nested class. To properly support this, generated code should be annotated with an @OriginatingElement annotation with the top-level class as the value. Note that this is not always the same as the enclosing class since there may be many layers of nesting.

For example, assume an extension is triggered by the following code and generates a module called FooTest_FooModule.

Java
Kotlin
@HiltAndroidTest
public class FooTest {
  @GenerateMyModule
  private Foo foo = new Foo();
  ...
}
@HiltAndroidTest
class FooTest {
  @GenerateMyModule
  val foo: Foo = Foo()
  ...
}

Then the generated FooTest_FooModule would need to be annotated like so:

Java
Kotlin
@OriginatingElement(FooTest.class)
@Module
@InstallIn(SingletonComponent.class)
interface FooTest_FooModule {
  ...
}
@OriginatingElement(FooTest::class)
@Module
@InstallIn(SingletonComponent::class)
interface FooTest_FooModule {
  ...
}