### Bazel: Dagger Android Setup Source: https://github.com/google/dagger/blob/master/README.md Load Dagger Android artifacts and repositories, then add them to maven_install. Call dagger_android_rules in your top-level BUILD file. ```python # Top-level WORKSPACE file load( "@dagger//:workspace_defs.bzl", "DAGGER_ANDROID_ARTIFACTS", "DAGGER_ANDROID_REPOSITORIES" ) maven_install( artifacts = DAGGER_ANDROID_ARTIFACTS + [...], repositories = DAGGER_ANDROID_REPOSITORIES + [...], ) ``` ```python # Top-level BUILD file load("@dagger//:workspace_defs.bzl", "dagger_android_rules") dagger_android_rules() ``` ```python deps = [ ":dagger-android", # For Dagger Android ":dagger-android-support", # For Dagger Android (Support) ] ``` -------------------------------- ### Bazel: Dagger Setup Source: https://github.com/google/dagger/blob/master/README.md Load Dagger artifacts and repositories, then add them to maven_install. Call dagger_rules in your top-level BUILD file to add Dagger build targets. ```python # Top-level WORKSPACE file load(@dagger//:workspace_defs.bzl, "DAGGER_ARTIFACTS", "DAGGER_REPOSITORIES") maven_install( artifacts = DAGGER_ARTIFACTS + [...], repositories = DAGGER_REPOSITORIES + [...], ) ``` ```python # Top-level BUILD file load(@dagger//:workspace_defs.bzl, "dagger_rules") dagger_rules() ``` ```python deps = [ ":dagger", # For Dagger ":dagger-spi", # For Dagger SPI ":dagger-producers", # For Dagger Producers ] ``` -------------------------------- ### Install Android SDK Components with sdkmanager Source: https://github.com/google/dagger/blob/master/CONTRIBUTING.md Installs necessary Android SDK components for building Dagger's Android targets. Ensure ANDROID_HOME is set correctly. This command may need to be run on Linux. ```bash $ANDROID_HOME/tools/bin/sdkmanager "platforms;android-34" "build-tools;34.0.0" ``` -------------------------------- ### Bazel: Hilt Android Setup Source: https://github.com/google/dagger/blob/master/README.md Load Hilt Android artifacts and repositories, then add them to maven_install. Call hilt_android_rules in your top-level BUILD file. ```python # Top-level WORKSPACE file load( "@dagger//:workspace_defs.bzl", "HILT_ANDROID_ARTIFACTS", "HILT_ANDROID_REPOSITORIES" ) maven_install( artifacts = HILT_ANDROID_ARTIFACTS + [...], repositories = HILT_ANDROID_REPOSITORIES + [...], ) ``` ```python # Top-level BUILD file load("@dagger//:workspace_defs.bzl", "hilt_android_rules") hilt_android_rules() ``` ```python deps = [ ":hilt-android", # For Hilt Android ":hilt-android-testing", # For Hilt Android Testing ] ``` -------------------------------- ### Install Dagger Local Snapshot Source: https://github.com/google/dagger/blob/master/CONTRIBUTING.md Builds and installs Dagger libraries into your local Maven repository with a LOCAL-SNAPSHOT version. This script is useful for testing local changes. ```bash ./util/install-local-snapshot.sh ``` -------------------------------- ### Installing Modules in Hilt Components Source: https://context7.com/google/dagger/llms.txt Use @InstallIn to specify the Hilt component for a @Module. Different scopes like SingletonComponent, ActivityComponent, FragmentComponent, and ViewModelComponent are available. ```java // Singleton scope — lives as long as the Application @Module @InstallIn(SingletonComponent.class) public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build(); } } // Activity scope — new instance per Activity @Module @InstallIn(ActivityComponent.class) public class UiModule { @Provides @ActivityScoped SnackbarManager provideSnackbarManager(Activity activity) { return new SnackbarManager(activity); } } // Fragment scope — new instance per Fragment @Module @InstallIn(FragmentComponent.class) abstract class FragmentModule { @Binds @FragmentScoped abstract Navigator bindNavigator(FragmentNavigator impl); } // ViewModel scope @Module @InstallIn(ViewModelComponent.class) abstract class ViewModelModule { @Binds @ViewModelScoped abstract Repository bindRepository(RepositoryImpl impl); } // Component hierarchy (parent → child): // SingletonComponent → ActivityRetainedComponent → ActivityComponent → FragmentComponent // → ViewComponent // → ServiceComponent // → ViewModelComponent ``` -------------------------------- ### Hilt Application Setup with @HiltAndroidApp Source: https://context7.com/google/dagger/llms.txt @HiltAndroidApp annotates the Application class to trigger Dagger component generation. It generates a base class that sets up the singleton component and handles injection. ```java // With Hilt Gradle Plugin (recommended — infers superclass automatically) @HiltAndroidApp public final class MyApplication extends Application { @Inject Analytics analytics; @Override public void onCreate() { super.onCreate(); // Injection happens in super.onCreate() analytics.initialize(); } } ``` ```java // Without Hilt Gradle Plugin (manual superclass) @HiltAndroidApp(Application.class) public final class MyApplication extends Hilt_MyApplication { @Inject Analytics analytics; @Override public void onCreate() { super.onCreate(); analytics.initialize(); } } ``` ```gradle // gradle (app/build.gradle) // dependencies { // implementation "com.google.dagger:hilt-android:2.x" // annotationProcessor "com.google.dagger:hilt-compiler:2.x" // } // plugins { id 'com.google.dagger.hilt.android' } ``` -------------------------------- ### Dagger @Module and @Provides Example Source: https://context7.com/google/dagger/llms.txt Use @Module to mark a class as contributing bindings and @Provides to annotate methods that return dependencies. Method parameters are satisfied by the graph. Ensure nullability is annotated with @Nullable if applicable. ```java @Module class NetworkModule { private final String baseUrl; NetworkModule(String baseUrl) { this.baseUrl = baseUrl; } @Provides @Singleton OkHttpClient provideOkHttpClient() { return new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .build(); } @Provides @Singleton Retrofit provideRetrofit(OkHttpClient client) { return new Retrofit.Builder() .baseUrl(baseUrl) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); } @Provides @Nullable String provideNullableToken() { return null; // must annotate with @Nullable to allow null } } ``` -------------------------------- ### Dagger @Binds Scope Mismatch Example Source: https://github.com/google/dagger/wiki/Dagger-2.17-@Binds-bugs Illustrates a scenario where a @Binds method is installed in a parent component but has a scope annotation matching a child component. This configuration would incorrectly compile in Dagger versions prior to 2.17 due to the binding floating down to the child component. ```java import javax.inject.Singleton; @Singleton @Component(modules = FooModule.class) interface ParentComponent { ChildComponent child(); } @Module abstract class FooModule { @Binds @ChildScope abstract Foo bind(FooImpl fooImpl); } @ChildScope @Subcomponent interface ChildComponent { Foo foo(); } ``` -------------------------------- ### Dagger Transitive Dependency Resolution Bug Example Source: https://github.com/google/dagger/wiki/Dagger-2.17-@Binds-bugs Demonstrates a bug where a @Binds method in a parent component has a transitive dependency (Crayons) that is only available in a child component. In older Dagger versions, the binding would 'float down' to the child component, causing compilation to succeed incorrectly. The fix involves ensuring all dependencies are available in the component where the module is installed. ```java @Component(modules = SkyBlueModule.class) interface ParentComponent { ChildComponent child(); } @Module abstract class SkyBlueModule { @Binds Blue skyBlue(SkyBlue sky); } class SkyBlue implements Blue { @Inject SkyBlue(Crayons crayons); } @Subcomponent(modules = CrayonsModule.class) interface ChildComponent { Blue blue(); } @Module class CrayonsModule { @Provides Crayons crayons() { return Crayons.new128ColorsBox(); } } ``` -------------------------------- ### Use dagger.Lazy for Deferred and Memoized Injection Source: https://context7.com/google/dagger/llms.txt Employ `dagger.Lazy` to defer the creation of an object until its first use. Subsequent calls to `get()` on the same `Lazy` instance will return the cached object, unlike `Provider` which creates a new instance each time. ```java class ReportGenerator { // Heavy database connection deferred until first use @Inject Lazy lazyDb; // Provider gives a new instance each call; Lazy memoizes after first call @Inject Provider provider; void generateReport() { if (needsDb()) { // computed once here, reused on subsequent calls DatabaseConnection db = lazyDb.get(); db.query("SELECT ..."); } // provider.get() returns a fresh ExpensiveObject every time ExpensiveObject obj = provider.get(); } } ``` -------------------------------- ### Declaring an Injector Interface with @Component Source: https://context7.com/google/dagger/llms.txt Annotate an interface with @Component to generate a Dagger implementation. List modules and dependencies. Use provision methods to get instances and members-injection methods to inject existing ones. ```java @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) interface AppComponent { // Provision method — Dagger returns a fully-injected instance CoffeeMaker coffeeMaker(); // Members-injection method — Dagger injects fields/methods of an existing instance void inject(MainActivity activity); // Subcomponent factory method UserComponent.Factory userComponentFactory(); @Component.Factory interface Factory { AppComponent create( @BindsInstance Application application, NetworkModule networkModule); } } // Instantiation via generated factory AppComponent component = DaggerAppComponent.factory() .create(application, new NetworkModule("https://api.example.com")); // Provision CoffeeMaker maker = component.coffeeMaker(); // Members injection component.inject(mainActivity); ``` -------------------------------- ### Bazel: Import Dagger Repository Source: https://github.com/google/dagger/blob/master/README.md Import the Dagger repository into your WORKSPACE file using http_archive. Ensure the http_archive points to a tagged release. ```python # Top-level WORKSPACE file load(@bazel_tools//tools/build_defs/repo:http.bzl, "http_archive") DAGGER_TAG = "2.59.2" DAGGER_SHA = "e9767696fdef2dd4cbf4d7eb2714425dc62d10222c2588d360f2afdbce1f4ff7" http_archive( name = "dagger", strip_prefix = "dagger-dagger-%s" % DAGGER_TAG, sha256 = DAGGER_SHA, urls = ["https://github.com/google/dagger/archive/dagger-%s.zip" % DAGGER_TAG], ) ``` -------------------------------- ### Other Build Systems: Include Dagger JARs Source: https://github.com/google/dagger/blob/master/README.md For build systems other than Bazel, include dagger-2.x.jar at runtime and dagger-compiler-2.x.jar at compile time to enable code generation. ```text You will need to include the `dagger-2.x.jar` in your application's runtime. In order to activate code generation and generate implementations to manage your graph you will need to include `dagger-compiler-2.x.jar` in your build at compile time. ``` -------------------------------- ### Component Instantiation with @Component.Builder and @Component.Factory Source: https://context7.com/google/dagger/llms.txt Use @Component.Builder for a fluent builder pattern or @Component.Factory for a single-method factory to instantiate components. @BindsInstance binds external instances into the component graph. ```java @Singleton @Component(modules = {AppModule.class, BackendModule.class}) interface AppComponent { Repository repository(); @Component.Builder interface Builder { @BindsInstance Builder application(Application app); @BindsInstance Builder baseUrl(@BaseUrl String url); Builder backendModule(BackendModule module); // required: has constructor params AppComponent build(); } } // Build via builder AppComponent component = DaggerAppComponent.builder() .application(myApp) .baseUrl("https://api.example.com") .backendModule(new BackendModule(timeout = 30)) .build(); // Alternatively with @Component.Factory (all-at-once): @Component.Factory interface Factory { AppComponent create( @BindsInstance Application app, @BindsInstance @BaseUrl String baseUrl, BackendModule backendModule); } AppComponent component = DaggerAppComponent.factory() .create(myApp, "https://api.example.com", new BackendModule(30)); ``` -------------------------------- ### @Component.Builder and @Component.Factory - Component Instantiation Source: https://context7.com/google/dagger/llms.txt `@Component.Builder` defines a fluent builder for the component; `@Component.Factory` defines a single-method factory. Use `@BindsInstance` on builder methods or factory parameters to bind external instances into the component graph. ```APIDOC ## @Component.Builder and @Component.Factory — Component Instantiation `@Component.Builder` defines a fluent builder for the component; `@Component.Factory` defines a single-method factory. Use `@BindsInstance` on builder methods or factory parameters to bind external instances into the component graph. ```java @Singleton @Component(modules = {AppModule.class, BackendModule.class}) interface AppComponent { Repository repository(); @Component.Builder interface Builder { @BindsInstance Builder application(Application app); @BindsInstance Builder baseUrl(@BaseUrl String url); Builder backendModule(BackendModule module); // required: has constructor params AppComponent build(); } } // Build via builder AppComponent component = DaggerAppComponent.builder() .application(myApp) .baseUrl("https://api.example.com") .backendModule(new BackendModule(timeout = 30)) .build(); // Alternatively with @Component.Factory (all-at-once): @Component.Factory interface Factory { AppComponent create( @BindsInstance Application app, @BindsInstance @BaseUrl String baseUrl, BackendModule backendModule); } AppComponent component = DaggerAppComponent.factory() .create(myApp, "https://api.example.com", new BackendModule(30)); ``` ``` -------------------------------- ### Creating Entry Points for Non-Hilt Classes Source: https://context7.com/google/dagger/llms.txt Use @EntryPoint to define an interface for accessing Hilt bindings from classes not managed by Hilt. Retrieve bindings using EntryPoints.get(). ```java // Define the entry point @EntryPoint @InstallIn(SingletonComponent.class) public interface DatabaseEntryPoint { AppDatabase database(); UserDao userDao(); } // Retrieve in a ContentProvider (not managed by Hilt) public class MyContentProvider extends ContentProvider { private UserDao userDao; @Override public boolean onCreate() { DatabaseEntryPoint ep = EntryPoints.get( getContext().getApplicationContext(), DatabaseEntryPoint.class); userDao = ep.userDao(); return true; } } // Custom WorkManager Worker public class SyncWorker extends Worker { private final SyncManager syncManager; public SyncWorker(Context context, WorkerParameters params) { super(context, params); SyncEntryPoint ep = EntryPoints.get(context.getApplicationContext(), SyncEntryPoint.class); this.syncManager = ep.syncManager(); } } ``` -------------------------------- ### Assemble Maps with @IntoMap and @StringKey Source: https://context7.com/google/dagger/llms.txt Use `@Binds @IntoMap` with a `@MapKey` annotation (like `@StringKey`) to contribute entries to a `Map` binding. This enables multiple modules to provide different command implementations mapped by string keys. ```java // --- Map multibindings --- @Module interface CommandsModule { @Binds @IntoMap @StringKey("login") Command login(LoginCommand cmd); @Binds @IntoMap @StringKey("logout") Command logout(LogoutCommand cmd); @Binds @IntoMap @StringKey("help") Command help(HelpCommand cmd); } // Custom enum map key @MapKey @interface CommandKey { CommandType value(); } @Module class EnumCommandModule { @Provides @IntoMap @CommandKey(CommandType.DEPOSIT) Command provideDeposit(DepositCommand cmd) { return cmd; } } // Injection class CommandRouter { @Inject CommandRouter(Map commands) { this.commands = commands; // {"login": ..., "logout": ..., "help": ...} } } ``` -------------------------------- ### Gradle Dependencies for Dagger and Hilt Source: https://context7.com/google/dagger/llms.txt Configure your build.gradle file to include Dagger core, Dagger Android (legacy), and Hilt for Android dependencies. Remember to use 'kapt' for Kotlin projects. Hilt testing dependencies are also included. ```groovy // build.gradle (Dagger core — Java/Android) dependencies { implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' // Kotlin projects: use kapt instead // kapt 'com.google.dagger:dagger-compiler:2.x' // Dagger Android (legacy) implementation 'com.google.dagger:dagger-android:2.x' implementation 'com.google.dagger:dagger-android-support:2.x' annotationProcessor 'com.google.dagger:dagger-android-processor:2.x' // Hilt for Android implementation 'com.google.dagger:hilt-android:2.x' annotationProcessor 'com.google.dagger:hilt-android-compiler:2.x' // Hilt testing androidTestImplementation 'com.google.dagger:hilt-android-testing:2.x' androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.x' testImplementation 'com.google.dagger:hilt-android-testing:2.x' testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.x' // Dagger Producers implementation 'com.google.dagger:dagger-producers:2.x' } ``` -------------------------------- ### @Inject - Constructor, Field, and Method Injection Source: https://context7.com/google/dagger/llms.txt Marks a constructor, field, or method as an injection point. Dagger automatically supplies the dependencies. Constructor injection is preferred for testability. ```APIDOC ## @Inject — Constructor, Field, and Method Injection Marks a constructor, field, or method as an injection point. Dagger will supply the dependencies automatically. Constructor injection is preferred as it keeps classes testable without a DI framework. ```java // Constructor injection (preferred) class CoffeeMaker { private final Heater heater; private final Pump pump; @Inject CoffeeMaker(Heater heater, Pump pump) { this.heater = heater; this.pump = pump; } Coffee brew() { heater.heat(); pump.pump(); return new Coffee(); } } // Field injection (for classes you don't control construction of) class MyActivity extends Activity { @Inject CoffeeMaker coffeeMaker; // injected by Dagger after construction @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // coffeeMaker is already injected after super.onCreate() with Hilt } } ``` ``` -------------------------------- ### Assemble Sets with @IntoSet and @ElementsIntoSet Source: https://context7.com/google/dagger/llms.txt Use `@Binds @IntoSet` to add individual elements to a `Set` binding, and `@Provides @ElementsIntoSet` to contribute a pre-existing `Set` to the collection. This allows multiple modules to contribute to a single set. ```java // --- Set multibindings --- @Module abstract class PluginModule { @Binds @IntoSet abstract Plugin bindAnalytics(AnalyticsPlugin p); @Binds @IntoSet abstract Plugin bindLogging(LoggingPlugin p); @Provides @ElementsIntoSet static Set provideDefaultPlugins() { return ImmutableSet.of(new CrashPlugin(), new MetricsPlugin()); } } // Inject the assembled set class PluginHost { @Inject PluginHost(Set plugins) { plugins.forEach(Plugin::initialize); } } ``` -------------------------------- ### Gradle dagger.android Dependencies Source: https://github.com/google/dagger/blob/master/README.md Include dagger-android and dagger-android-support if you are using classes in dagger.android. Use dagger-android-processor for annotation processing. ```groovy implementation 'com.google.dagger:dagger-android:2.x' implementation 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries annotationProcessor 'com.google.dagger:dagger-android-processor:2.x' ``` -------------------------------- ### Find Bazel Binary Location Source: https://github.com/google/dagger/blob/master/CONTRIBUTING.md Locates the Bazel executable on your system. This command is used to configure the Bazel binary path in Android Studio if it cannot be found automatically. ```bash where bazel ``` -------------------------------- ### Assisted Injection with @AssistedInject and @Assisted Source: https://context7.com/google/dagger/llms.txt Assisted injection allows some constructor parameters to be provided by Dagger and others by the caller at creation time. The compiler generates an @AssistedFactory implementation. ```java // Step 1: Mark the constructor with @AssistedInject; caller-supplied params with @Assisted class DataService { private final DataFetcher dataFetcher; // from Dagger private final Config config; // from caller @AssistedInject DataService(DataFetcher dataFetcher, @Assisted Config config) { this.dataFetcher = dataFetcher; this.config = config; } } ``` ```java // Multiple @Assisted params of the same type need identifiers class SearchService { @AssistedInject SearchService( Analytics analytics, @Assisted("query") String query, @Assisted("locale") String locale) { /* ... */ } } ``` ```java // Step 2: Define the factory interface @AssistedFactory interface DataServiceFactory { DataService create(Config config); } ``` ```java @AssistedFactory interface SearchServiceFactory { SearchService create( @Assisted("query") String query, @Assisted("locale") String locale); } ``` ```java // Step 3: Inject the factory and use it class MyApp { @Inject DataServiceFactory dataServiceFactory; @Inject SearchServiceFactory searchServiceFactory; void run() { DataService svc = dataServiceFactory.create(new Config("production")); SearchService search = searchServiceFactory.create("dagger", "en-US"); } } ``` -------------------------------- ### Maven Dependencies for Older Compiler Versions Source: https://github.com/google/dagger/blob/master/README.md For maven-compiler-plugin versions lower than 3.5, add dagger-compiler with the 'provided' scope. ```xml com.google.dagger dagger 2.x com.google.dagger dagger-compiler 2.x provided ``` -------------------------------- ### Dagger @Binds for Interface Binding Source: https://context7.com/google/dagger/llms.txt Use @Binds in an abstract @Module for efficient interface-to-implementation binding. The parameter type must be assignable to the return type. This is more efficient than @Provides. Can be combined with qualifiers and multibindings. ```java @Module abstract class StorageModule { // Binds SharedPrefsStorage (the impl) to Storage (the interface) @Binds @Singleton abstract Storage bindStorage(SharedPrefsStorage impl); // Qualified binding using a @Qualifier annotation @Binds @Singleton @InMemory abstract Cache bindInMemoryCache(LruCache lruCache); // Combining @Binds with multibindings @Binds @IntoSet abstract Plugin bindLoggingPlugin(LoggingPlugin loggingPlugin); } ``` -------------------------------- ### Define and Use Custom Qualifiers for Same-Type Bindings Source: https://context7.com/google/dagger/llms.txt Use custom `@Qualifier` annotations to distinguish between multiple bindings of the same type. This is essential when providing different instances, like separate Retrofit clients for production and staging environments. ```java // Define qualifiers @Qualifier @Retention(RUNTIME) @interface Production {} @Qualifier @Retention(RUNTIME) @interface Staging {} // Module providing two different Retrofit instances @Module class ApiModule { @Provides @Singleton @Production Retrofit provideProductionRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com/") .build(); } @Provides @Singleton @Staging Retrofit provideStagingRetrofit() { return new Retrofit.Builder() .baseUrl("https://staging.example.com/") .build(); } } // Injection site uses the qualifier to pick the right binding class ApiClient { @Inject ApiClient(@Production Retrofit retrofit) { /* ... */ } } ``` ```java // Named qualifier from javax.inject (no custom annotation needed) @Module class ConfigModule { @Provides @Named("apiKey") String provideApiKey() { return "abc123"; } @Provides @Named("timeout") int provideTimeout() { return 30; } } class ServiceClient { @Inject @Named("apiKey") String apiKey; @Inject @Named("timeout") int timeout; } ``` -------------------------------- ### Gradle Dagger Dependencies Source: https://github.com/google/dagger/blob/master/README.md Add Dagger dependencies to your Gradle build file using 'implementation' for better compilation performance. Use 'annotationProcessor' for the compiler. ```groovy // Add Dagger dependencies dependencies { implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' } ``` -------------------------------- ### Maven Dependencies and Compiler Configuration Source: https://github.com/google/dagger/blob/master/README.md Include the dagger artifact in your dependencies and dagger-compiler in annotationProcessorPaths for the maven-compiler-plugin. Ensure the plugin version is at least 3.6.1. ```xml com.google.dagger dagger 2.x org.apache.maven.plugins maven-compiler-plugin 3.6.1 com.google.dagger dagger-compiler 2.x ``` -------------------------------- ### Dagger Producers for Asynchronous Operations Source: https://context7.com/google/dagger/llms.txt Utilize Dagger Producers for asynchronous dependency injection with `ListenableFuture`. Producer methods return futures, and Dagger schedules them on a provided executor. Requires an `@Production` Executor binding. ```java // Producer module with async bindings @ProducerModule class SearchModule { @Produces ListenableFuture loadIndex(IndexLoader loader) { return loader.loadAsync(); // async I/O } @Produces ListenableFuture search( SearchIndex index, @Assisted String query) { return index.searchAsync(query); } @Produces ListenableFuture renderResults(SearchResults results, Renderer renderer) { return renderer.renderAsync(results); } } // Production component — requires @Production Executor binding @ProductionComponent(modules = {SearchModule.class, ExecutorModule.class}) interface SearchComponent { ListenableFuture searchResults(); } @Module class ExecutorModule { @Provides @Production Executor provideExecutor() { return Executors.newFixedThreadPool(4); } } // Usage SearchComponent component = DaggerSearchComponent.create(); ListenableFuture htmlFuture = component.searchResults(); Futures.addCallback(htmlFuture, new FutureCallback() { @Override public void onSuccess(Html html) { render(html); } @Override public void onFailure(Throwable t) { handleError(t); } }, executor); ``` -------------------------------- ### Maven Dependencies for Dagger Source: https://context7.com/google/dagger/llms.txt Add Dagger core dependencies to your Maven pom.xml. Ensure the dagger-compiler is included in the maven-compiler-plugin's annotationProcessorPaths. ```xml // Maven (pom.xml) // // com.google.dagger // dagger // 2.x // // // // com.google.dagger // dagger-compiler // 2.x // ``` -------------------------------- ### Marking Android Classes for Hilt Injection Source: https://context7.com/google/dagger/llms.txt Use @AndroidEntryPoint to enable Hilt injection for Android framework classes. Fields are injected before onCreate/onAttach. ```java // Activity @AndroidEntryPoint public final class HomeActivity extends AppCompatActivity { @Inject UserRepository userRepository; @Inject AnalyticsService analytics; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // userRepository and analytics injected here setContentView(R.layout.activity_home); userRepository.loadCurrentUser().observe(this, user -> { /* ... */ }); } } // Fragment @AndroidEntryPoint public final class ProfileFragment extends Fragment { @Inject ProfileViewModel.Factory viewModelFactory; @Override public void onAttach(Context context) { super.onAttach(context); } } // Service @AndroidEntryPoint public final class SyncService extends Service { @Inject SyncManager syncManager; @Override public int onStartCommand(Intent intent, int flags, int startId) { syncManager.sync(); return START_NOT_STICKY; } } ``` -------------------------------- ### Declare Optional Bindings with @BindsOptionalOf Source: https://context7.com/google/dagger/llms.txt Use @BindsOptionalOf to declare types that may or may not be present in the Dagger component. Consumers can inject Optional, Optional>, or Optional>. ```java @Module interface OptionalModule { // Declare Foo as optionally present @BindsOptionalOf Foo optionalFoo(); // With qualifier @BindsOptionalOf @Debug Foo optionalDebugFoo(); } ``` ```java // Consumer adapts behavior based on presence class FeatureService { private final Optional debugLogger; @Inject FeatureService(Optional debugLogger) { this.debugLogger = debugLogger; } void doWork() { debugLogger.ifPresent(log -> log.log("Starting doWork")); // ... actual work ... } } ``` ```java // If DebugLogger IS bound in the component, Optional will be present. // If it is NOT bound, Optional will be absent — no compile error. ``` -------------------------------- ### Constructor and Field Injection with @Inject Source: https://context7.com/google/dagger/llms.txt Use @Inject for constructor injection to keep classes testable. Field injection is suitable for classes whose construction cannot be controlled. ```java class CoffeeMaker { private final Heater heater; private final Pump pump; @Inject CoffeeMaker(Heater heater, Pump pump) { this.heater = heater; this.pump = pump; } Coffee brew() { heater.heat(); pump.pump(); return new Coffee(); } } class MyActivity extends Activity { @Inject CoffeeMaker coffeeMaker; // injected by Dagger after construction @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // coffeeMaker is already injected after super.onCreate() with Hilt } } ``` -------------------------------- ### Legacy Dagger Android Injection with `@ContributesAndroidInjector` Source: https://context7.com/google/dagger/llms.txt Use `@ContributesAndroidInjector` within a `@Module` to generate subcomponent injectors for Android classes. Ensure Android classes implement `HasAndroidInjector` and call `AndroidInjection.inject()` or `AndroidSupportInjection.inject()`. ```java // Application: implement HasAndroidInjector class MyApp extends Application implements HasAndroidInjector { @Inject DispatchingAndroidInjector androidInjector; @Override public void onCreate() { super.onCreate(); DaggerAppComponent.create().inject(this); } @Override public AndroidInjector androidInjector() { return androidInjector; } } // Module: declare injectors for each Android class @Module abstract class AndroidBindingModule { @ContributesAndroidInjector(modules = LoginModule.class) abstract LoginActivity contributeLoginActivity(); @ContributesAndroidInjector abstract HomeFragment contributeHomeFragment(); @ContributesAndroidInjector(modules = SyncModule.class) abstract SyncService contributeSyncService(); } // Activity: call AndroidInjection.inject(this) in onCreate class LoginActivity extends Activity { @Inject LoginViewModel viewModel; @Override protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); // must be before super.onCreate() super.onCreate(savedInstanceState); } } // Fragment: call AndroidSupportInjection.inject(this) in onAttach class HomeFragment extends Fragment { @Inject HomePresenter presenter; @Override public void onAttach(Context context) { AndroidSupportInjection.inject(this); super.onAttach(context); } } ``` -------------------------------- ### Dagger @Subcomponent for Scoped Child Components Source: https://context7.com/google/dagger/llms.txt Declare a subcomponent in a parent module's `subcomponents` attribute or via a factory method. Subcomponents inherit bindings from the parent and can add their own scoped bindings. Use @Subcomponent.Factory for creating instances with @BindsInstance. ```java @PerSession @Subcomponent(modules = {UserModule.class, CartModule.class}) interface UserSessionComponent { CheckoutService checkoutService(); ShoppingCart cart(); @Subcomponent.Factory interface Factory { UserSessionComponent create(@BindsInstance User user); } } // Parent module declares the subcomponent @Module(subcomponents = UserSessionComponent.class) class AppModule { /* ... */ } // Parent component exposes the factory @Singleton @Component(modules = AppModule.class) interface AppComponent { UserSessionComponent.Factory userSessionFactory(); } // At runtime: create a session subcomponent per logged-in user UserSessionComponent sessionComponent = appComponent .userSessionFactory() .create(loggedInUser); CheckoutService checkout = sessionComponent.checkoutService(); // Session ends: drop reference to sessionComponent ``` -------------------------------- ### Gradle Java Compile Options for Max Errors Source: https://github.com/google/dagger/blob/master/README.md Increase the number of errors javac will print for projects using Android Databinding library. This prevents databinding compilation from halting prematurely when Dagger prints many errors. ```groovy gradle.projectsEvaluated { tasks.withType(JavaCompile) { options.compilerArgs << "-Xmaxerrs" << "500" // or whatever number you want } } ``` -------------------------------- ### Dagger Custom @Scope Annotations Source: https://context7.com/google/dagger/llms.txt Define custom scopes using @Retention(RUNTIME), @Scope, @Documented, and @interface to manage binding lifetimes. Apply scopes to components and bindings to ensure single instances within the component's lifetime. @Singleton is used for app-lifetime singletons. ```java // Define a custom scope @Retention(RUNTIME) @Scope @Documented @interface PerActivity {} // Apply to a component @PerActivity @Subcomponent(modules = ActivityModule.class) interface ActivityComponent { void inject(MainActivity activity); } // Apply to a binding — one instance per ActivityComponent instance @PerActivity class PresenterFactory { @Inject PresenterFactory(Repository repo, Analytics analytics) { /* ... */ } } // @Singleton on a @Provides method — one instance per AppComponent instance @Module class AuthModule { @Provides @Singleton AuthManager provideAuthManager(TokenStore store) { return new AuthManager(store); } } ``` -------------------------------- ### @Component - Declaring the Injector Interface Source: https://context7.com/google/dagger/llms.txt Annotates an interface or abstract class for which Dagger generates a fully-formed, dependency-injected implementation. The generated class is named `Dagger`. The component must list its `modules` and optionally its `dependencies`. ```APIDOC ## @Component — Declaring the Injector Interface Annotates an interface or abstract class for which Dagger generates a fully-formed, dependency-injected implementation. The generated class is named `Dagger`. The component must list its `modules` and optionally its `dependencies`. ```java @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) interface AppComponent { // Provision method — Dagger returns a fully-injected instance CoffeeMaker coffeeMaker(); // Members-injection method — Dagger injects fields/methods of an existing instance void inject(MainActivity activity); // Subcomponent factory method UserComponent.Factory userComponentFactory(); @Component.Factory interface Factory { AppComponent create( @BindsInstance Application application, NetworkModule networkModule); } } // Instantiation via generated factory AppComponent component = DaggerAppComponent.factory() .create(application, new NetworkModule("https://api.example.com")); // Provision CoffeeMaker maker = component.coffeeMaker(); // Members injection component.inject(mainActivity); ``` ``` -------------------------------- ### Apply @Reusable Scope for Pooled Instances Source: https://context7.com/google/dagger/llms.txt Use the `@Reusable` scope for stateless, potentially expensive-to-create objects where sharing is acceptable but not strictly guaranteed. This annotation suggests that an instance may be reused across components and requests. ```java @Module class UtilModule { @Provides @Reusable // may be cached and reused, but not guaranteed singleton JsonParser provideJsonParser() { return new JsonParser(); } @Provides @Reusable ImageLoader provideImageLoader(OkHttpClient client) { return new ImageLoader(client); } } ``` -------------------------------- ### Maven Dependency for dagger-producers Source: https://github.com/google/dagger/blob/master/README.md Add the dagger-producers artifact to your Maven dependencies if you are using the dagger-producers extension for parallelizable execution graphs. ```xml com.google.dagger dagger-producers 2.x ``` -------------------------------- ### Declare Empty Multibindings with @Multibinds Source: https://context7.com/google/dagger/llms.txt Use `@Multibinds` on an abstract module method to declare the existence of a `Set` or `Map` binding, even if no elements or entries are contributed. This prevents missing-binding errors when a set or map might legitimately be empty. ```java @Module interface PluginModule { // Declares that Set exists even if no @IntoSet contributions are made @Multibinds Set plugins(); // Declares an empty Map fallback @Multibinds Map commands(); } ``` -------------------------------- ### Custom Map Keys with @MapKey Source: https://context7.com/google/dagger/llms.txt Use @MapKey to define custom annotation types for use as map keys in @IntoMap multibindings. Keys can be primitives, Strings, Classes, enums, or other annotations. ```java // Enum key @MapKey @interface ActivityKey { Class value(); } ``` ```java @Module abstract class ActivityModule { @Binds @IntoMap @ActivityKey(LoginActivity.class) abstract AndroidInjector.Factory bindLoginActivity(LoginActivity.Factory f); @Binds @IntoMap @ActivityKey(HomeActivity.class) abstract AndroidInjector.Factory bindHomeActivity(HomeActivity.Factory f); } ``` ```java // Composite annotation key (unwrapValue = false) @MapKey(unwrapValue = false) @interface RouteKey { String path(); HttpMethod method(); } ``` ```java @Module class RouteModule { @Provides @IntoMap @RouteKey(path = "/users", method = HttpMethod.GET) Handler provideGetUsersHandler() { return new GetUsersHandler(); } } ``` -------------------------------- ### Hilt Android Instrumentation Testing with `@BindValue` Source: https://context7.com/google/dagger/llms.txt Use `@HiltAndroidTest` and `HiltAndroidRule` for Hilt-enabled instrumentation tests. Replace real bindings with test doubles using `@BindValue` or `@BindValueIntoSet`. ```java import androidx.test.ext.junit.runners.AndroidJUnit4; import dagger.hilt.android.testing.HiltAndroidRule; import dagger.hilt.android.testing.HiltAndroidTest; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import androidx.test.core.app.ActivityScenarioRule; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; import javax.inject.Inject; @HiltAndroidTest @RunWith(AndroidJUnit4.class) public class HomeActivityTest { // Rule must be first (before ActivityScenarioRule) @Rule(order = 0) public HiltAndroidRule hiltRule = new HiltAndroidRule(this); @Rule(order = 1) public ActivityScenarioRule activityRule = new ActivityScenarioRule<>(HomeActivity.class); // Replace the real UserRepository binding with this test double @BindValue UserRepository fakeRepo = new FakeUserRepository(); // Replace a multibinding contribution @BindValueIntoSet Plugin testPlugin = new NoOpPlugin(); @Inject Analytics analytics; @Before public void setUp() { hiltRule.inject(); // must call before accessing injected fields } @Test public void displaysUserName() { fakeRepo.setUser(new User("Ada Lovelace")); activityRule.getScenario().onActivity(activity -> { onView(withId(R.id.username_text)).check(matches(withText("Ada Lovelace"))); }); } } ``` -------------------------------- ### Define Custom Hilt Component with Scope Source: https://context7.com/google/dagger/llms.txt Use @DefineComponent to declare a new Hilt component outside the standard hierarchy. This allows for custom scopes like per-user or per-flow. Ensure the custom scope annotation is annotated with @Scope and @Retention(RUNTIME). ```java // Define a custom scope annotation @Retention(RUNTIME) @Scope @interface LoggedInScoped {} // Define the custom component @LoggedInScoped @DefineComponent(parent = SingletonComponent.class) interface UserComponent {} // Define its builder @DefineComponent.Builder interface UserComponentBuilder { UserComponentBuilder bindUser(@BindsInstance User user); UserComponent build(); } // Install modules into the custom component @Module @InstallIn(UserComponent.class) abstract class UserModule { @Binds @LoggedInScoped abstract UserPreferences bindPreferences(UserPreferencesImpl impl); } // Access the custom component builder via EntryPoints @EntryPoint @InstallIn(SingletonComponent.class) interface UserComponentBuilderEntryPoint { UserComponentBuilder userComponentBuilder(); } class SessionManager { @Inject Application app; UserComponent createUserSession(User user) { return EntryPoints.get(app, UserComponentBuilderEntryPoint.class) .userComponentBuilder() .bindUser(user) .build(); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.