Search code examples
androidkotlindagger-2dagger-hilt

Dagger/DuplicateBindings with generic interfaces even when using qualifier annotation


I have a base Interface defined like this:

@JvmSuppressWildcards
abstract class IWorkerContract<T, R>(
    private val mContext: Context,
    // Some other stuff
) {
    private val ctx: CoroutineScope = CoroutineScope(Job())

    // Some other stuff
}

Now, I have two classes that implement this interface

class ShopItemProductDescWorkerContract @Inject constructor(
    // Some other stuff
) : IWorkerContract<@JvmSuppressWildcards List<ShopItemDescription>,@JvmSuppressWildcards String>( // important part
    // Some other stuff
){

class ShopItemTechnicalDescWorkerContract @Inject constructor(
    // Some other stuff
) : IWorkerContract<@JvmSuppressWildcards List<ShopItemDescription>,@JvmSuppressWildcards String>(
    // Some other stuff
){

and then finally, in my module

@Module
@InstallIn(ViewModelComponent::class)
abstract class WorkerModule {
    @WorkerContract(EWorkerContracts.SHOP_ITEM_PROD)
    @Binds
    abstract fun bindShopItemProductDescWorkContract(sipContract: ShopItemProductDescWorkerContract): IWorkerContract<List<ShopItemDescription>, String>

    @WorkerContract(EWorkerContracts.SHOP_ITEM_TECH)
    @Binds
    abstract fun bindShopItemTechnicalDescWorkContract(sitContract: ShopItemTechnicalDescWorkerContract): IWorkerContract<List<ShopItemDescription>, String>

}

@Retention(AnnotationRetention.RUNTIME)
annotation class WorkerContract(val value: EWorkerContracts)

enum class EWorkerContracts {
    SHOP_ITEM_PROD,
    SHOP_ITEM_TECH
}

Error

error: [Dagger/DuplicateBindings] com.example.app.business.datasource.network.worker.list.IWorkerContract<java.util.List<com.example.app.business.domain.model.shop.item.ShopItemDescription>,java.lang.String> is bound multiple times:
  public abstract static class SingletonC implements App_GeneratedInjector,
                         ^
      @org.jetbrains.annotations.NotNull @Binds @com.example.app.di.business.network.WorkerContract(com.example.app.di.business.network.EWorkerContracts.SHOP_ITEM_PROD) com.example.app.business.datasource.network.worker.list.IWorkerContract<List<com.example.app.business.domain.model.shop.item.ShopItemDescription>,String> com.example.app.di.business.network.WorkerModule.bindShopItemProductDescWorkContract(com.example.app.business.datasource.network.worker.shop.item.productdesc.ShopItemProductDescWorkerContract)
      @org.jetbrains.annotations.NotNull @Binds @com.example.app.di.business.network.WorkerContract(com.example.app.di.business.network.EWorkerContracts.SHOP_ITEM_TECH) com.example.app.business.datasource.network.worker.list.IWorkerContract<List<com.example.app.business.domain.model.shop.item.ShopItemDescription>,String> com.example.app.di.business.network.WorkerModule.bindShopItemTechnicalDescWorkContract(com.example.app.business.datasource.network.worker.shop.item.technicaldesc.ShopItemTechnicalDescWorkerContract)
      com.example.app.business.datasource.network.worker.list.IWorkerContract<java.util.List<com.example.app.business.domain.model.shop.item.ShopItemDescription>,java.lang.String> is injected at
          com.example.app.business.interactor.shop.item.ShopItemInteractor(shopItemProductWorkerContract, �)
      com.example.app.business.interactor.shop.item.ShopItemInteractor is injected at
          com.example.app.presentation.shop.item.core.ShopItemViewModel(shopItemInteractor, �)
      com.example.app.presentation.shop.item.core.ShopItemViewModel is injected at
          com.example.app.presentation.shop.item.core.ShopItemViewModel_HiltModules.BindsModule.binds(vm)
      @dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at
          dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.example.app.presentation.App_HiltComponents.SingletonC ? com.example.app.presentation.App_HiltComponents.ActivityRetainedC ? com.example.app.presentation.App_HiltComponents.ViewModelC]
  It is also requested at:
      com.example.app.business.interactor.shop.item.ShopItemInteractor(�, shopItemTechnicalWorkerContract, �)

Solution

  • You're not using @Named in the example, you're using @WorkerContract as a qualifier annotation. (@Named is a built-in qualifier annotation, but you can create your own as in your example.)

    However, you're missing the @Qualifier meta-annotation itself:

    Identifies qualifier annotations. Anyone can define a new qualifier. A qualifier annotation:

    • is annotated with @Qualifier, @Retention(RUNTIME), and typically @Documented.
    • [...]

    As @Documented is optional and only affects the Javadoc, make sure to add @Qualifier and you'll be good to go.

    @Qualifier
    @Retention(AnnotationRetention.RUNTIME)
    annotation class WorkerContract(val value: EWorkerContracts)