Dagger 2 MissingBinding при замене конкреции на интерфейс - PullRequest
1 голос
/ 02 мая 2020

У меня есть два класса, которые я могу заставить Dagger найти и ввести для успешного использования:

TrackEvent

class TrackEvent @Inject constructor(
    private val getTrackingProperties: SomeClass
) : UseCase<Boolean, TrackingEvent> {

    override suspend operator fun invoke(params: TrackingEvent): Boolean {
        return true
    }

SomeClass (примечание: используется в качестве зависимости в TrackEvent)

class SomeClass @Inject constructor() {
    override suspend operator fun invoke(): UserTrackingPropertiesResult {
        return UserTrackingPropertiesResult()
    }
}

TrackEvent имеет запись в аннотированном интерфейсе @Module, поскольку это реализация интерфейса UseCase:

@Component(modules = [MyModule::class])
interface ShiftsComponent {
    fun inject(homeFragment: HomeFragment)
}

@Module
interface MyModule {

    @Binds
    fun bindsTrackEventUseCase(useCase: TrackEvent): UseCase<Boolean, TrackingEvent>
}

Интерфейсы прецедентов

interface UseCase<out T, in P> {

    suspend operator fun invoke(params: P): T
}

interface NoParamUseCase<out T> {

    suspend operator fun invoke(): T
}

Я хотел бы добавить интерфейс в TrackEvent вместо конкретного SomeClass. Поэтому я заставляю SomeClass реализовать NoParamUseCase

class SomeClass @Inject constructor(): NoParamUseCase<UserTrackingPropertiesResult> {
    override suspend operator fun invoke(): UserTrackingPropertiesResult {
        return UserTrackingPropertiesResult()
    }
}

обновление TrackEvent для внедрения интерфейса:

class TrackEvent @Inject constructor(
    private val getTrackingProperties: NoParamUseCase<UserTrackingPropertiesResult>) : UseCase<Boolean, TrackingEvent> {

    override suspend operator fun invoke(params: TrackingEvent): Boolean {
        return true
    }
}

… и обновить MyModule, чтобы сообщить Dagger о какой реализации Я хотел бы использовать:

@Module
interface MyModule {

    @Binds
    fun bindsTrackEventUseCase(useCase: TrackEvent): UseCase<Boolean, TrackingEvent>

    // New
    @Binds
    fun bindsSomeClass(useCase: SomeClass): NoParamUseCase<UserTrackingPropertiesResult>
}

Теперь Даггер утверждает, что отсутствует привязка и что мне нужно объявить аннотированный метод @Provides:

error: [Dagger/MissingBinding] com.myapp.core.domain.usecase.NoParamUseCase<? extends com.myapp.core.tracking.UserTrackingPropertiesResult> cannot be provided without an @Provides-annotated method.
public abstract interface MyComponent {
                ^
      com.myapp.core.domain.usecase.NoParamUseCase<? extends com.myapp.core.tracking.UserTrackingPropertiesResult> is injected at
          com.myapp.tasks.tracking.domain.usecase.TrackEvent(getTrackingProperties, …)
          …

Насколько Я могу сказать, что это не так:

  • Хотя в этом случае я выбрал @Binds, заменив его на @Provides и предоставив здесь зависимости вручную, вы получите ту же ошибку.
  • Я использую точно такой же подход для класса TrackEvent, и это работает.
  • Я изменил only в том, что я хотел бы предоставить интерфейс вместо. Я бы полностью понял эту ошибку, если бы я не предоставил объявление @Binds.

Это отличается от этого вопроса , поскольку нет никакой двусмысленности относительно того, какую реализацию я спрашиваю Кинжал использовать так, как если бы у меня было две или более реализации одного и того же интерфейса.

Почему я получил бы эту ошибку сейчас?

1 Ответ

1 голос
/ 05 мая 2020

Согласно сообщению об ошибке кинжала, он ожидает ковариантный тип NoParamUseCase<? extends UserTrackingPropertiesResult>, но модуль DI предоставляет инвариант NoParamUseCase<UserTrackingPropertiesResult>. Чтобы сгенерировать соответствующую подпись для , предоставьте метод , вы можете изменить его следующим образом:

@Binds fun bindsSomeClass(useCase: SomeClass): NoParamUseCase<@JvmWildcard UserTrackingPropertiesResult>

После этого ваш код должен быть успешно скомпилирован.

...