Search code examples
androiddaggerdagger-hiltdependency-inversion

Dagger Hilt Incompatibility with Dependency Inversion


In an Android project structured to follow the Dependency Inversion Principle (DIP) as outlined in the Android Developer's guide on modularization patterns, I've encountered a challenge with Dagger Hilt dependency injections across modules.

The project's architecture initially mixed public abstractions and private implementations across three modules:

  • :feature:A
  • :common:B
  • :lib:C

To adhere to DIP, the project was restructured into:

  • Public Abstraction modules
    • :feature:A
    • :common:B
    • :lib:C
  • Private implementation modules
    • :feature:A:impl
    • :common:B:impl
    • :lib:C:impl

Dagger Hilt is utilized for dependency injection, with all bindings located in the impl modules. The issue arises when attempting to inject an implementation from :common:B:impl into :feature:A:impl, where :common:B:impl also requires an injection from :lib:C:impl. While injections work as expected when the implementations and bindings for C remain in :lib:C (not fully adhering to DIP), moving them to :lib:C:impl leads to errors. The error I encountered is a missing binding error when :common:B:impl needs to be injected into :feature:A:impl:

/Users/user/AndroidStudioProjects/project/app/build/generated/hilt/component_sources/projectProdDebug/com/project/app/common/app/ProjectApplication_HiltComponents.java:1054: error: [Dagger/MissingBinding] com.project.app.backend.IServiceProviderFromModuleB cannot be provided without an  method.
  public abstract static class SingletonC implements StatusVerified.StatusVerifiedComponent,
                         ^

      com.project.app.backend.IServiceProviderFromModuleB is injected at
          [com.project.app.common.app.ProjectApplication_HiltComponents.SingletonC] com.project.appdata.network.DataProviderFromModuleA(serviceProvider, …)

This error suggests that Dagger Hilt cannot find a way to provide an instance of IServiceProviderFromModuleB for injection, despite the expected setup in the :common:B:impl module. This scenario typically indicates a misconfiguration or misunderstanding of how Dagger Hilt manages dependencies across modules, especially when adhering to DIP.

I'm seeking insights or solutions to resolve this binding issue, ensuring that the project's structure both adheres to DIP and allows for successful dependency injections across modules using Dagger Hilt.

Does anybody have an idea?


Solution

  • TL;DR:

    The issue was caused by having modules with the same name, leading to incorrect Hilt bindings generation - MissingBinding error. Renaming the module from :lib:C:impl to :lib:C:impl2 fixed the problem.

    This relates to a known Gradle issue: https://github.com/gradle/gradle/issues/847, which was supposedly fixed years ago but seems to have resurfaced.