Home Tutorials Training Consulting Books Company Contact us


Get more...

This article describes the usage of Dagger 2 within standard Java applications and within Android applications.

1. Introduction to the concept of dependency injection

See Dependency Injection for an introduction into the concept of dependency injection.

2. Dependency injection with Dagger 2

2.1. What is Dagger 2?

Dagger 2 is dependency injection framework. It is based on the Java Specification Request (JSR) 330. It uses code generation and is based on annotations. The generated code is very relatively easy to read and debug.

Dagger 2 uses the following annotations:

  • @Module and @Provides: define classes and methods which provide dependencies

  • @Inject: request dependencies. Can be used on a constructor, a field, or a method

  • @Component: enable selected modules and used for performing dependency injection

Dagger 2 uses generated code to access the fields and not reflection. Therefore it is not allowed to use private fields for field injection.

2.2. Defining dependency providers (object providers)

The term dependency injection context is typically used to describe the set of objects which can be injected.

In Dagger 2, classes annotated with @Module are responsible for providing objects which can be injected. Such classes can define methods annotated with @Provides. The returned objects from these methods are available for dependency injection.

Methods annotated with @Provides can also express dependencies via method parameters. These dependencies are fulfilled by Dagger 2, if possible.

2.3. Defining dependencies (object consumers)

You use the @Inject annotation to define a dependency. If you annotate a constructor with @Inject, Dagger 2 can also use an instance of this object to fulfill dependencies. This was done to avoid the definition of lots of @Provides methods for these objects.

2.4. Connecting consumers and providers

The @Component is used on an interface. Such an interface is used by Dagger 2 to generate code. The base pattern for the generated class is that Dagger is used as prefix followed by the interface name. This generate class has a create method which allows configuring the objects based on the given configuration. The methods defined on the interface are available to access the generated objects.

A @Component interface defines the connection between provider of objects (modules) and the objects which expresses a dependency. The following table gives an overview of the usage of the Dagger annotations.

Table 1. Annotation summary of Dagger 2
Annotation Usage

@Module

Used on classes which contains methods annotated with @Provides.

@Provides

Can be used on methods in classes annotated with @Module and is used for methods which provides objects for dependencies injection.

@Singleton

Single instance of this provided object is created and shared.

@Component

Used on an interface. This interface is used by Dagger 2 to generate code which uses the modules to fulfill the requested dependencies.

2.5. Scope annotations

You can use the @Singleton annotation to indicate that there should be only one instance of the object.

2.6. Special treatment of fields in Dagger

Dagger 2 does not inject fields automatically. It can also not inject private fields. If you want to use field injection you have to define a method in your @Component interface which takes the instance into which you want to inject as parameter.

2.7. Using Dagger 2 with Eclipse and Maven

To use Eclipse and Maven together with Dagger 2 you can install the Maven tooling and the apt plug-in which allows Maven to configure the annotation processors.

For Eclipse Maven support use the update site of your release and afterwards install the m2e-apt tooling via the http://download.jboss.org/jbosstools/updates/m2e-extensions/m2e-apt update site.

After the installation you must enable apt-processing on via the Eclipse preferences in Window  Preferences  Maven  Annotation Processing. Select Automatically configure JDT APT.

Maven apt processing configuration

3. Exercise: Dependency injection with Dagger 2

In this example you use Dagger 2 in a standard Java program managed by Maven.

This exercise can be done via any Java IDE you like, for example the Eclipse IDE with the Maven tooling installed. Or it can be developed and compiled via a text editor and the Maven command line. If you use Eclipse, ensure to install the Eclipse Maven tooling.

3.1. Create example project for the usage of Dagger 2

Create a new Maven project with the com.vogella.java.dagger2 top level package.

3.2. Define or adjust Maven build file

Adjust your pom.xml to the following.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vogella.java.dagger2</groupId>
    <artifactId>com.vogella.java.dagger2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>com.vogella.java.dagger2</name>

    <dependencies>
        <dependency>
            <groupId>com.google.dagger</groupId>
            <artifactId>dagger</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>com.google.dagger</groupId>
            <artifactId>dagger-compiler</artifactId>
            <version>2.4</version>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3.3. Define classes which have a dependency

Define the following two classes which express dependencies.

package com.vogella.java.dagger2;

import jakarta.inject.Inject;

public class User {
    
    private String firstName;
    private String lastName;
    
    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "User [firstName=" + firstName + ", lastName=" + lastName + "]";
    }
}
package com.vogella.java.dagger2;

import jakarta.inject.Inject;

public class BackendService {
    
    @Inject
    public User user;
    
    private String serverUrl;
    
    @Inject
    public BackendService(@Named("serverUrl") String serverUrl) {
        this.serverUrl = serverUrl;
    }
    
    public boolean callServer() {
        if (user !=null && serverUrl!=null && serverUrl.length()>0) {
            System.out.println("User: " + user + " ServerUrl: "  + serverUrl);
            return true;
        }
        return false;
    }
}

3.4. Define modules which provides dependencies

Define two class which acts as providers for dependencies.

package com.vogella.java.dagger2.modules;

import jakarta.inject.Named;
import javax.inject.Singleton;

import com.vogella.java.dagger2.BackendService;

import dagger.Module;
import dagger.Provides;

@Module
public class BackEndServiceModule {
    
    @Provides
    @Singleton
    BackendService provideBackendService(@Named("serverUrl") String serverUrl) {
       return new BackendService(serverUrl);
    }
    
    @Provides
    @Named("serverUrl")
    String provideServerUrl() {
       return "https://www.vogella.com/";
    }
    
    @Provides
    @Named("anotherUrl")
    String provideAnotherUrl() {
       return "http://www.google.com";
    }

}
package com.vogella.java.dagger2.modules;

import javax.inject.Singleton;

import com.vogella.java.dagger2.User;

import dagger.Module;
import dagger.Provides;

@Module
public class UserModule {

    @Provides
    @Singleton
    User providesUser() {
        return new User("Lars", "Vogel");
    }
}

3.5. Define components

Components define from which modules (or other components) dependencies are provided. Dagger 2 uses this interface to generate the accessor class which provides the methods defined in the interface.

package com.vogella.java.dagger2.component;

import javax.inject.Singleton;

import com.vogella.java.dagger2.BackendService;
import com.vogella.java.dagger2.modules.BackEndServiceModule;
import com.vogella.java.dagger2.modules.UserModule;

import dagger.Component;

@Singleton
@Component(modules = { UserModule.class, BackEndServiceModule.class })
public interface MyComponent {

    // provide the dependency for dependent components
    // (not needed for single-component setups)
    BackendService provideBackendService();
    
    // allow to inject into our Main class
    // method name not important
    void inject(Main main); (1)
}
1 Method which allows injecting into BackendServer for the fields

3.6. Use the generated dagger code

The usage of the generated code is demonstrated by the following test class.

package com.vogella.java.dagger2.main;

import com.vogella.java.dagger2.BackendService;
import com.vogella.java.dagger2.component.DaggerMyComponent;
import com.vogella.java.dagger2.component.MyComponent;

public class Main {

    @Inject
    BackendService backendService; // (1)

    private MyComponent component;

    private Main() {
        component = DaggerMyComponent.builder().build();
        component.inject(this);
    }

    private void callServer() {
        boolean callServer = backendService.callServer();
        if (callServer) {
            System.out.println("Server call was successful. ");
        } else {
            System.out.println("Server call failed. ");
        }
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.callServer();
    }
}
1 Fields are not automatically injected hence the method call to inject the fields

4. Dagger 2 and Android

4.1. Using dependency injection with Android

Many Android components, e.g. activities, are instantiated by the Android framework and not in your code. This makes it difficult to supply dependencies via constructors to Android components.

4.2. Using Dagger 2 in Android

To enable Dagger 2 add the following dependencies to your build.gradle file.

compile 'com.google.dagger:dagger:2.10'
annotationProcessor 'com.google.dagger:dagger-compiler:2.10'

If you want to use classes from the dagger.android package, like DaggerActivity, also add the following dependencies to your build.gradle file. This is also needed, if you want to inject Activities components like activities or fragments.

compile 'com.google.dagger:dagger-android:2.10'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.10'

If you want to use the support libraries with Dagger 2, you also have to add the following to your build.gradle

compile 'com.google.dagger:dagger-android-support:2.10'

5. Exercise: Dependency injection in Android activities with Dagger 2

In this exercise the usage of the Dagger 2 dependency injection framework in an Android application is demonstrated. In our simple app, there is an activity that allows a user to authenticate his credentials. The result value of the implementation is displayed in a text field.

Android studio does not build the project automatically, hence you frequently get compile errors because the generated code is not yet there. Select Build  Make Project to trigger the generation of the code.

5.1. Create project

Create a new project with the top level package com.vogella.android.dagger2simple. Use the Empty Activity template.

The activity layout file should look similar to the following:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".MainActivity">

    <TextView
        android:id="@+id/target"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello"
        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large"/>
</LinearLayout>

5.2. Enter Gradle dependencies

Add the following dependencies to your app/build.gradle file.

compile 'com.google.dagger:dagger:2.11'
compile 'com.google.dagger:dagger-android:2.11'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'

If you are getting an like Error:Conflict with dependency 'com.google.code.findbugs:jsr305' in project ':app' you can add the following to your app/build.gradle file.

android {
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
    }
}

5.3. Define your dependency graph

As mentioned above, Android components (activities, fragments, etc.) are instantiated by the Android framework which makes it difficult to use dependency injection on them. Fortunately, Dagger provides classes that simplifies the dependency injection into Android components.

Create a class named NetworkApi. This class will be injected into the activity.

package com.vogella.android.dagger2simple;

import jakarta.inject.Inject;

public class NetworkApi {

    @Inject
    public NetworkApi(){
    }

    public boolean validateUser(String username, String password) {
        // imagine an actual network call here
        // for demo purpose return false in "real" life
        if (username == null || username.length() == 0) {
            return false;
        } else {
            return true;
        }
    }
}

With the @Inject annotation on the constructor, we instruct Dagger that an object of this class can be injected into other objects. Dagger automatically calls this constructor, if an instance of this class is requested.

Adjust your activity to receive an instance of NetworkApi. This demonstrates the dependency injection with the NetworkApi.

package com.vogella.android.dagger2simple;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import jakarta.inject.Inject;

import dagger.android.AndroidInjection;

public class MainActivity extends Activity {

    @Inject
    NetworkApi networkApi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        boolean injected = networkApi == null ? false : true;
        TextView userAvailable = (TextView) findViewById(R.id.target);
        userAvailable.setText("Dependency injection worked: " + String.valueOf(injected));
    }
}

Create am application object.

package com.vogella.android.dagger2simple;

import android.app.Activity;
import android.app.Application;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
    }
}

Register the Application class via the manifest like the following.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.vogella.android.dagger2simple" >

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Create a module named MyApplicationModule like the following.

package com.vogella.android.dagger2simple;


import dagger.Module;
import dagger.Provides;
import dagger.android.ContributesAndroidInjector;

@Module
public abstract class MyApplicationModule {
    @ContributesAndroidInjector
    abstract MainActivity contributeActivityInjector();
}

It extends the AndroidInjector to perform injection on a concrete Android component type (in our case MainActivity).

5.4. Update your Application class and prepare dependency injection

Create an interface called MyApplicationComponent. This component is responsible for injecting the Application class.

package com.vogella.android.dagger2simple;

import dagger.Component;
import dagger.android.AndroidInjectionModule;
import dagger.android.AndroidInjector;

@Component(modules = { AndroidInjectionModule.class, MyApplicationModule.class})
public interface MyApplicationComponent extends AndroidInjector<MyApplication> {
}

In the @Component annotation the modules are specified which are used to create the implementation of the component. While we reference our ActivityModule to inject activities, we also reference the AndroidInjectionModule which is needed to ensure the binding of the Android base types (Activities, Fragments, etc.).

Adjust MyApplication to the following.

package com.vogella.android.dagger2simple;

import android.app.Activity;
import android.app.Application;

import jakarta.inject.Inject;

import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasActivityInjector;

public class MyApplication extends Application implements HasActivityInjector {
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerMyApplicationComponent.create().inject(this);
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}

Select Build  Make Project to trigger the generation of the code.

Here, we use our MyApplicationComponent (now prefixed with Dagger) to inject our Application class. This way a DispatchingAndroidInjector is injected which is then returned when an injector for an activity is requested (through activityInjector()).

5.5. Validate

Run your application, the user interface should report that dependency injection worked. If not, have a look at the generated classes in the app/build/generated/apt folder. The generated classes by Dagger are well structured and should give a hint what went wrong.

5.6. Optional: Use the @Provides annotation

If you have a class that you want to make injectable and you are not allowed to change it (to annotate the constructor), you have the possibility to provide a new static method to your module that returns an instance of that class to make it injectable. If you prefer this way, remove the @Inject annotation from the NetworkApi constructor, and add the following lines to your ActivityModule class.

    @Provides
    static NetworkApi provideNetworkApi(){
        return new NetworkApi();
    }

6. Replacing @Module classes in tests

For tests you can your custom modules and setup Dagger to use them. The generated builder of Dagger contains methods to set the module. You can use the Dagger build to replace the generated class with the one which should be used for testing.

This also works well with Mockito. Assume you have the following class you want to test.

public class ImportantClass {
    private MyRestService restService;
    private MyLogger logger;

    @Inject public MainService(MyRestService restService, MyLogger logger) {
        this.restService = restService;
        this.logger = logger;
    }

    public void perform() {
        String s = restService.getData();
        logger.write(s.toUpperCase());
    }
}

You can test this class with Mockito.

public class ImportantClassTest {

public class MainServiceTest {

    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock MyRestService restService;

    @Mock MyLogger logger;

    @InjectMocks ImportantClass importClassToBeTested;

    @Test
    public void performShouldWriteOutput() {
        when(restService.getData()).thenReturn("abc");

        importClassToBeTested.perform();

        verify(logger).print("ABC");
    }
}
}

Better support for replacing Dagger dependencies is offered by https://github.com/fabioCollini/DaggerMock.

7. Dagger resources