- 1. Introduction to the concept of dependency injection
- 2. Dependency injection with Dagger 2
- 3. Exercise: Dependency injection with Dagger 2
- 4. Dagger 2 and Android
- 5. Exercise: Dependency injection in Android with Dagger 2
- 6. Replacing @Module classes in tests
- 7. About this website
- 8. Dagger resources
- Appendix A: Copyright and License
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
In Dagger it is not allowed to use private fields for field injection as Dagger 2 uses generated code to access the fields and not reflection.
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.
Annotation | Usage |
---|---|
| Used on classes which contains methods annotated with |
| Can be used on methods in classes annotated with |
| Single instance of this provided object is created and shared. |
| 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 Automatically configure JDT APT.
. Select
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 javax.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 javax.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 javax.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 "http://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);
}
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;
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();
}
}
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 adjust your build.gradle project file.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0-alpha3'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Add the following entries to your app/build.gradle file.
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 22
buildToolsVersion "23.0.0"
defaultConfig {
applicationId "com.vogella.android.dagger2simple"
minSdkVersion 22
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
ext {
JUNIT_VERSION = '4.12'
DAGGER_VERSION ='2.4'
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.dagger:dagger:2.4'
apt "com.google.dagger:dagger-compiler:DAGGER_VERSION"
provided 'javax.annotation:jsr250-api:1.0'
compile 'javax.inject:javax.inject:1'
testCompile "junit:junit:$JUNIT_VERSION"
testApt "com.google.dagger:dagger-compiler:DAGGER_VERSION"
}
You need to configure apt for each scope in which Dagger should be used. For example |
5. Exercise: Dependency injection in Android with Dagger 2
5.1. Target of this exercise
In this exercise Dagger 2 is demonstrated in an Android application. In our simple app, there is an activity that allows a user to authenticate some credentials. The result value of the implementation is displayed in a text field.
5.2. Create project
Create a new project with the top level package com.vogella.android.dagger2simple
.
Adjust the layout file of the generated activity.
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/target"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
5.3. Enter Gradle dependencies
Add the following entries to your build.gradle project file.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0-alpha3'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Add the following entries to your app/build.gradle file.
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 22
buildToolsVersion "23.0.0"
defaultConfig {
applicationId "com.vogella.android.dagger2simple"
minSdkVersion 22
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
ext {
JUNIT_VERSION = '4.12'
DAGGER_VERSION ='2.4'
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.dagger:dagger:2.4'
apt "com.google.dagger:dagger-compiler:DAGGER_VERSION"
provided 'javax.annotation:jsr250-api:1.0'
compile 'javax.inject:javax.inject:1'
testCompile "junit:junit:$JUNIT_VERSION"
testApt "com.google.dagger:dagger-compiler:DAGGER_VERSION"
}
5.4. Define your dependencies graph
Create the following classes for providing dependencies and wiring them up.
package com.vogella.android.dagger2simple;
public class 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;
}
}
}
package com.vogella.android.dagger2simple.modules;
import com.vogella.android.dagger2simple.NetworkApi;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class NetworkApiModule {
@Provides
@Singleton
public NetworkApi getNetwork(){
return new NetworkApi();
}
}
package com.vogella.android.dagger2simple.components;
import android.app.Activity;
import com.vogella.android.dagger2simple.MainActivity;
import com.vogella.android.dagger2simple.NetworkApi;
import com.vogella.android.dagger2simple.modules.NetworkApiModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {NetworkApiModule.class})
public interface DiComponent {
// to update the fields in your activities
void inject(MainActivity activity);
}
5.5. Wiring up the application
Create the following implementation for your Application
class. This class builds up the dependency injection context and gives access to it, via the getComponent
method.
package com.vogella.android.dagger2simple;
import android.app.Application;
import com.vogella.android.dagger2simple.components.DaggerDiComponent;
import com.vogella.android.dagger2simple.components.DiComponent;
public class MyApplication extends Application {
DiComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerDiComponent.builder().build();
}
public DiComponent getComponent() {
return component;
}
}
Of course this class needs to registered via the manifest.
<?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>
The activity injects the created values into it via the method defined on the @Component class.
package com.vogella.android.dagger2simple;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import javax.inject.Inject;
public class MainActivity extends Activity {
@Inject NetworkApi networkApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication) getApplication()).getComponent().inject(this);
boolean injected = networkApi == null ? false : true;
TextView userAvailable = (TextView) findViewById(R.id.target);
userAvailable.setText("Dependency injection worked: " + String.valueOf(injected));
}
}
5.6. 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.

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. About this website
8. Dagger resources
8.1. vogella GmbH training and consulting support
TRAINING | SERVICE & SUPPORT |
---|---|
The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”. | The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers. |