A fast dependency injector for Java and Android that generates plain Java source code without using reflection or runtime bytecode generation
—
The module system in Dagger defines how dependencies are constructed and provided to the dependency injection container. Modules contain provider methods and binding methods that tell Dagger how to create instances of various types.
Annotates classes that contribute bindings to the object graph. Modules can include other modules and declare subcomponents.
/**
* Annotates classes that contribute bindings to the object graph
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Module {
/**
* Additional modules to include in this module
*/
Class<?>[] includes() default {};
/**
* Subcomponent classes that can be created from this module
*/
Class<?>[] subcomponents() default {};
}Usage Examples:
// Basic module
@Module
public class DatabaseModule {
@Provides
@Singleton
DatabaseConnection provideConnection() {
return new DatabaseConnection("localhost", 5432);
}
}
// Module including other modules
@Module(includes = {NetworkModule.class, CacheModule.class})
public class AppModule {
@Provides
AppService provideAppService(ApiClient client, Cache cache) {
return new AppService(client, cache);
}
}
// Module with subcomponents
@Module(subcomponents = UserSubcomponent.class)
public class ApplicationModule {
// Module bindings...
}Annotates methods in modules to create provider method bindings. The method's return type is bound to the value returned by the method.
/**
* Annotates methods in modules to create provider method bindings
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Provides {}Key Features:
Usage Examples:
@Module
public class NetworkModule {
// Simple provider
@Provides
@Singleton
OkHttpClient provideHttpClient() {
return new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build();
}
// Provider with dependencies
@Provides
ApiService provideApiService(OkHttpClient client, Gson gson) {
return new Retrofit.Builder()
.baseUrl("https://api.example.com")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(ApiService.class);
}
// Qualified provider
@Provides
@Named("api-key")
String provideApiKey() {
return BuildConfig.API_KEY;
}
// Nullable provider
@Provides
@Nullable
CacheConfig provideCacheConfig() {
return BuildConfig.DEBUG ? null : new CacheConfig();
}
}Annotates abstract methods in modules for delegation bindings. More efficient than @Provides methods that just return an injected parameter.
/**
* Annotates abstract methods in modules for delegation bindings
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Binds {}Key Features:
Usage Examples:
@Module
public abstract class RepositoryModule {
// Bind interface to implementation
@Binds
abstract UserRepository bindUserRepository(UserRepositoryImpl impl);
// Bind with qualifier
@Binds
@Named("local")
abstract DataSource bindLocalDataSource(LocalDataSource impl);
// Bind into set
@Binds
@IntoSet
abstract Validator bindEmailValidator(EmailValidator impl);
// Bind into map
@Binds
@IntoMap
@StringKey("user")
abstract Repository bindUserRepository(UserRepository impl);
// Can mix with @Provides in same module
@Provides
static Database provideDatabase() {
return Room.databaseBuilder(...)
.build();
}
}Declares bindings for Optional containers of values that may or may not be present in the dependency graph.
/**
* Annotates abstract methods that declare optional bindings
* @Beta This API is subject to incompatible changes
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface BindsOptionalOf {}Key Features:
Usage Examples:
@Module
public abstract class OptionalModule {
// Declare optional binding
@BindsOptionalOf
abstract Optional<FeatureFlag> optionalFeatureFlag();
// Optional provider
@BindsOptionalOf
abstract Optional<Provider<ExpensiveService>> optionalExpensiveService();
}
// Usage in injected class
public class FeatureService {
private final Optional<FeatureFlag> featureFlag;
@Inject
public FeatureService(Optional<FeatureFlag> featureFlag) {
this.featureFlag = featureFlag;
}
public boolean isFeatureEnabled() {
return featureFlag.map(FeatureFlag::isEnabled).orElse(false);
}
}Modules can include other modules to compose larger binding graphs.
// Base modules
@Module
public class NetworkModule {
@Provides @Singleton
OkHttpClient provideHttpClient() { /* ... */ }
}
@Module
public class DatabaseModule {
@Provides @Singleton
Database provideDatabase() { /* ... */ }
}
// Composed module
@Module(includes = {NetworkModule.class, DatabaseModule.class})
public class AppModule {
@Provides
AppService provideAppService(OkHttpClient client, Database database) {
return new AppService(client, database);
}
}Provider methods can be static for better performance when they don't need instance state.
@Module
public abstract class UtilityModule {
@Provides
static Gson provideGson() {
return new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
.create();
}
@Provides
static ExecutorService provideExecutorService() {
return Executors.newFixedThreadPool(4);
}
}Dagger performs compile-time validation of modules:
Granular Modules:
// Good: Specific responsibility
@Module
public class NetworkModule { /* ... */ }
@Module
public class DatabaseModule { /* ... */ }
// Avoid: Monolithic module
@Module
public class EverythingModule { /* ... */ }Prefer @Binds over @Provides:
// Preferred: More efficient
@Binds
abstract UserRepository bindUserRepository(UserRepositoryImpl impl);
// Less efficient
@Provides
UserRepository provideUserRepository(UserRepositoryImpl impl) {
return impl;
}Install with Tessl CLI
npx tessl i tessl/maven-com-google-dagger--dagger