Dagger внедряет интерфейс в приватные поля

Я хочу внедрить реализацию интерфейса в конструктор абстрактного класса и использовать его в дочернем классе.

У меня есть ошибки времени компиляции:

Error:Gradle: Dagger does not support injection into private fields
Error:Gradle: Example.A cannot be provided without an @Provides-annotated method.
Error:Gradle: Example.B cannot be provided without an @Inject constructor or from an @Provides-annotated method.
Error:Gradle: Execution failed for task ':app:compileDemoDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

Пример в котлине.

   object Example {
    interface IData {

        fun foo() {
        }
    }

    class Data : IData {

    }

    @Module
    class DataModel {
        @Provides
        fun data(): IData = Data()
    }

    @Singleton
    @Component(modules =
    arrayOf(DataModel::class)
    )
    interface Injector {
        fun inject(a: A)
        fun inject(b: B)
    }

    val graph: Injector = DaggerInjector.builder().
            dataModel(DataModel()).
            build()

    abstract class A {

        @Inject var data: IData ? = null

        public open fun setUp() {
            graph.inject(this)
        }
    }

    open class B : A() {

        override fun setUp() {
            super.setUp()
            data!!.foo()
        }
    }

    fun bar() {
        val a = B()
        a.setUp()
    }
}

версии:

  • com.android.tools.build:gradle:2.1.2
  • доб.котлин_версия = '1.0.3'
  • скомпилировать 'com.google.dagger:dagger:2.4'
  • предоставлено «org.glassfish: javax.annotation: 10.0-b28»
  • kapt 'com.google.dagger:dagger-compiler:2.4'

Вот случай. Декомпилированная Java

  public static class A {
  @Inject
  @Nullable
  private Example.IData data;

  @Nullable
  protected final Example.IData getData() {
     return this.data;
  }

  protected final void setData(@Nullable Example.IData <set-?>) {
     this.data = <set-?>;
  }

  public void setUp() {
     Example.INSTANCE.getGraph().inject(this);
  }

}


person punksta    schedule 10.07.2016    source источник


Ответы (1)


Из сообщения об ошибке я думаю, что проблема в этой строке:

@Inject var data: IData ? = null

Поддерживающее поле для этого свойства — private, и именно об этом говорит ошибка. Обычно для таких случаев используется ключевое слово lateinit:

@Inject lateinit var data: IData

lateinit — это один из нескольких модификаторов, которые отображают резервное поле непосредственно с уровнем доступа к свойству (здесь public), делая его видимым для классов, сгенерированных Dagger.

person AndroidEx    schedule 10.07.2016
comment
Спасибо. Я не мог понять, что происходит. данные защищены и могут быть изменены. - person punksta; 10.07.2016
comment
@StasShakirov, фрагмент, который вы приложили, декомпилирован после того, как вы применили lateinit, верно? Если вы сделаете то же самое с кодом перед lateinit, вы должны увидеть эту строку вместо private Example.IData data;. И поскольку dagger не использует сеттеры для заполнения полей @Inject, а пытается напрямую получить доступ к полю, в исходном случае он выдает ошибку. Это изменение видимости является побочным эффектом lateinit (в дополнение к его основному значению в Kotlin), потому что этот модификатор изначально был создан для поддержки внедрения зависимостей. - person AndroidEx; 10.07.2016
comment
Я немного опоздал с ответом на ваш комментарий :) Надеюсь, теперь это имеет смысл. - person AndroidEx; 10.07.2016
comment
Ха, интересно! Я никогда не знал, что lateinit выставляет поле поддержки. Я бы просто переместил @Inject в установщик свойства. - person Marcin Koziński; 11.07.2016