Migrating from Dagger 1

While Dagger 1 and Dagger 2 are similar in many ways, one is not a drop-in replacement for the other. This guide will highlight both the API and conceptual differences between the two versions and provide recommended patterns for migrating.

Injected types

Dagger 2 continues to rely on JSR 330 for declaring injection sites. All of the types of injection supported by Dagger 1 (field and constructor) continue to be supported by Dagger 2, but Dagger 2 supports method injection as well. Dagger 2 does not support static injection.

Framework types

Dagger 2 also continues to support both the JSR 330 and Dagger-specific framework types. Provider, Lazy and MembersInjector all maintain the same behavior.

Modules

Dagger 2 modules are very similar to Dagger 1 modules, but reduce much of the configuration complexity that had been a pain point for some. For most users, migration will simply be deleting properties.

Module Properties

The primary differences between the two stem from the fact that graph validation is no longer performed on a per-module basis. In Dagger 1 terms, Dagger 2 modules are all declared as complete = false and library = true, but since that is most permissive for validation complete, library and addsTo can just be removed when migrating.

Modules are no longer the mechanism for declaring which types can be accessed by calling code. So, the injects and staticInjections properties can be removed as well.

Dagger 2 doesn’t support overrides. Modules that override for simple testing fakes can create a subclass of the module to emulate that behavior. Modules that use overrides and rely on dependency injection should be decomposed so that the overriden modules are instead represented as a choice between two modules.

The remaining property, includes, is still the primary tool for composing modules and continues to behave as it always did.

@Provides methods

Provides methods have the exact same semantics.

Creating the graph

The mechanism by which the full, dependency-injected graph is built is the primary difference between Dagger 1 and Dagger 2. In Dagger 1 the graph was composed via reflection by ObjectGraph, but in Dagger 2 it is done by a @Component-annotated, user-defined type whose implementation is generated at compile time. Transitioning from ObjectGraph to @Component will likely be the majority of the work in any migration.

Declaring the component

In order to instantiate an ObjectGraph, users were required to supply a list of module classes or instances. A typical invocation might look like the following:

ObjectGraph.create(ModuleOne.class, ModuleTwo.class, new ModuleThree("hello!"));

Components separate defining the graph from instantiating it. A component definition requires the same information, but declared in the @Component’s modules parameter instead. An equivalent component named MyComponent would look like the following:

@Component(
  modules = {
    ModuleOne.class,
    ModuleTwo.class,
    ModuleThree.class,
  }
)
interface MyComponent {
  /* … */
}

As mentioned previously, @Module.injects was the mechanism for declaring which objects could be retrieved from the graph in Dagger 1. In Dagger 2, methods on the component interface fulfill the same role, but in a static, type-safe way. Any binding in the graph can be accessed via a component method.

If a caller to the ObjectGraph above were to ask for a Foo.class and a Bar.class and and inject members into an instance of Baz, the following component methods would serve those roles:

@Component(
  modules = {
    ModuleOne.class,
    ModuleTwo.class,
    ModuleThree.class,
  }
)
interface MyComponent {
  /* Functionally equivalent to objectGraph.get(Foo.class). */
  Foo getFoo();
  /* Functionally equivalent to objectGraph.get(Bar.class). */
  Bar getBar();
  /* Functionally equivalent to objectGraph.inject(aBaz). */
  Baz injectBaz(Baz baz);
}

More detail about defining components can be found in the Component javadocs.

Instantiating the component

The final task is to instantiate the component implementation. The Dagger 2 annotation processor generates implementations that have the same name as the component interface prepended with Dagger. For the MyComponent interface, the generated component is named DaggerMyComponent.

For component implementations that don’t have module instances to pass, instantiating the component is as simple as invoking the create() method. In this example, ModuleThree is passed as an instance, so the component’s builder is used instead.

MyComponent myComponent = DaggerMyComponent.builder()
    // ModuleOne and ModuleTwo don't need to be set explicitly
    .moduleThree(new ModuleThree("hello!"))
    .build();

More detail about instantiating components can be found in the Component javadocs as well.

Scope

Dagger 1 only supported a single scope: @Singleton. Dagger 2 allows users to any well-formed scope annotation. The Component docs describe the details of how to properly apply scope to a component.

Subgraphs

Dagger 1 provided ObjectGraph.plus as the mechanism for creating new graphs from existing ones. Dagger 2 has two mechanisms for composing graphs - each with its own advantages - but subcomponents is the most direct analog. Defining a subcomponent is very similar to defining a component and the component is associated with the subcomponent via a factory method that accepts the necessary modules. If the Dagger 1 code created a new subgraph by invoking objectGraph.plus(new ChildGraphModule("child!")), the following definition and invocation would have the same effect.

@Component(/* … */)
interface MyComponent {
  /* … */

  /* Functionally equivalent to objectGraph.plus(childGraphModule). */
  MySubcomponent plus(ChildGraphModule childGraphModule);
}
MySubcomponent mySubcomponent = myComponent.plus(new ChildGraphModule("child!"));

Subcomponents are further described in the @Subcomponent and the @Component javadoc.

Nullability

Unlike Dagger 1, Dagger 2 performs implicit null checking unless a @Nullable annotation (from any package) is present. During migration, applications may have to annotate injection sites and provides methods with the @Nullable of their choice. Any mismatch in nullability will be reported as a compile-time error.