In this
post, I will walk you through, how can we achieve dependency injection using
Dagger library.
Application
that we are going to develop
We are
going to implement ‘DataPrinter’ application, that reads data from a data
source and print it to the console. Here data source can be a MySQLDataSource,
FileDataSource etc.,
To work with
dagger, we need to use 'dagger-compiler' annotation processor to generate the
code at compile time.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>${dagger.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
DataPrinter
class looks like below.
DataPrinter.java
public class DataPrinter {
private DataSource sqlSource;
private DataSource fileSource;
@Inject
public DataPrinter(@Named("sql") DataSource sqlSource, @Named("file") DataSource fileSource) {
this.sqlSource = sqlSource;
this.fileSource = fileSource;
}
public void print() {
String dataFromSQL = sqlSource.read();
String dataFromFile = fileSource.read();
System.out.println(dataFromSQL);
System.out.println(dataFromFile);
}
}
As you see
the above snippet
a.
@Inject
annotation is applied on the constructor to inhect the dependencies for sqlSource
and fileSource.
b.
@Named
annotation is used to inject the bean by a qualifier name . It helps to differentiate
two objects of same type.
Define a module that provide dependencies
@Module
public class DependenciesProviderModule {
@Provides
@Named("sql")
public static DataSource provideMySqlDataSource() {
return new MySQLDataSource();
}
@Provides
@Named("file")
public static DataSource provideFileDataSource() {
return new FileDataSource();
}
}
Define
a component to generate injector
@Component(modules = {DependenciesProviderModule.class})
public interface DataPrinterComponent {
DataPrinter dataPrinter();
}
As you see
above snippet, we passed the modules information to the component, Dagger build
the DataPrinter dependencies using the modules specified in component
definition.
Generate
injector code
Navigate
to the pom.xml file and execute the command ‘mvn compile’ to generate the code
from annotations.
The classes starts with
Dagger are generated by Dagger library. We can use ‘DaggerDataPrinterComponent’
class to get an instance of DataPrinterComponent.
DataPrinterComponent dataPrinterComponent = DaggerDataPrinterComponent.builder().build();
DataPrinter dataPrinter = dataPrinterComponent.dataPrinter();
dataPrinter.print();
Find the
below working application.
Step 1: Create new maven project
‘dagger-hello-world’.
Step 2: Update pom.xml with maven dependencies.
pom.xml
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample.app</groupId>
<artifactId>dagger-hello-world</artifactId>
<version>1</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<dagger.version>2.44</dagger.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>${dagger.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.sample.app.App</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Step 3: Define DataSource.
DataSource.java
package com.sample.app.interfaces;
public interface DataSource {
public String read();
}
Step 4: Define DataSource implementations.
FileDataSource.java
package com.sample.app.interfaces.impl;
import com.sample.app.interfaces.DataSource;
public class FileDataSource implements DataSource{
@Override
public String read() {
return "Hi there!!!!!";
}
}
MySQLDataSource.java
package com.sample.app.interfaces.impl;
import com.sample.app.interfaces.DataSource;
public class MySQLDataSource implements DataSource{
@Override
public String read() {
return "hello world!!!!!";
}
}
Step 5: Define DataPrinter class.
DataPrinter.java
package com.sample.app.util;
import javax.inject.Inject;
import javax.inject.Named;
import com.sample.app.interfaces.DataSource;
public class DataPrinter {
private DataSource sqlSource;
private DataSource fileSource;
@Inject
public DataPrinter(@Named("sql") DataSource sqlSource, @Named("file") DataSource fileSource) {
this.sqlSource = sqlSource;
this.fileSource = fileSource;
}
public void print() {
String dataFromSQL = sqlSource.read();
String dataFromFile = fileSource.read();
System.out.println(dataFromSQL);
System.out.println(dataFromFile);
}
}
Step 6: Define module.
DependenciesProviderModule.java
package com.sample.app.modules;
import javax.inject.Named;
import com.sample.app.interfaces.DataSource;
import com.sample.app.interfaces.impl.FileDataSource;
import com.sample.app.interfaces.impl.MySQLDataSource;
import dagger.Module;
import dagger.Provides;
@Module
public class DependenciesProviderModule {
@Provides
@Named("sql")
public static DataSource provideMySqlDataSource() {
return new MySQLDataSource();
}
@Provides
@Named("file")
public static DataSource provideFileDataSource() {
return new FileDataSource();
}
}
Step 7: Define DataPrinterComponent.
DataPrinterComponent.java
package com.sample.app.components;
import com.sample.app.modules.DependenciesProviderModule;
import com.sample.app.util.DataPrinter;
import dagger.Component;
@Component(modules = {DependenciesProviderModule.class})
public interface DataPrinterComponent {
DataPrinter dataPrinter();
}
Step 8: Define main application class.
App.java
package com.sample.app;
import com.sample.app.components.DataPrinterComponent;
import com.sample.app.util.DataPrinter;
import com.sample.app.components.DaggerDataPrinterComponent;
public class App {
public static void main(String[] args) {
DataPrinterComponent dataPrinterComponent = DaggerDataPrinterComponent.builder().build();
DataPrinter dataPrinter = dataPrinterComponent.dataPrinter();
dataPrinter.print();
}
}
Total project
structure looks like below.
How to
generate the jar file?
Navigate to
the folder where pom.xml is located and execute below command.
mvn package
How to run
the jar file?
‘jar’ file is
located at target folder.
$ls -l target/*jar
-rw-r--r-- 1 krishna staff 49611 Oct 1 21:08 target/dagger-hello-world-1-jar-with-dependencies.jar
-rw-r--r-- 1 krishna staff 13103 Oct 1 21:08 target/dagger-hello-world-1.jar
As you see
there are two jars generated one with dependencies and other without
dependencies.
Run the jar
with dependencies by executing below command.
java -jar target/dagger-hello-world-1-jar-with-dependencies.jar
$java -jar target/dagger-hello-world-1-jar-with-dependencies.jar
hello world!!!!!
Hi there!!!!!
You can
download this application from this link.
References
https://dagger.dev/dev-guide/
Previous
Next
Home