Avatar ·

Ошибка Dagger: "Prefer to run the dagger processor over that class instead" в Kotlin

Всем привет! Перевожу проект с Java на Kotlin, и столкнулся с проблемой при использовании Dagger 2. У меня есть простой модуль, который предоставляет зависимость: ```kotlin @Module class NetworkModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com") .build() } } @Component(modules = [NetworkModule::class]) @Singleton interface AppComponent { fun inject(activity: MainActivity) } ``` Но когда я запускаю сборку, Gradle выдаёт ошибку: `error: [Dagger/DependencyCycle] Prefer to run the dagger processor over that class instead` Я погуглил, но все решения либо для Java, либо не подходят. У меня используется Kotlin 1.8, Dagger 2.48, kapt. Пробовал чистить кеш, пересобирать — не помогает. Ошибка возникает именно на этапе генерации Dagger-компонентов. В чём может быть дело? Может, из-за того, что я использую `@Singleton` без `@Reusable`? Или это известная проблема с Kotlin и Dagger? Буду благодарен за любые подсказки, так как проект горит по срокам. <<>>

Причина ошибки

Ошибка Prefer to run the dagger processor over that class instead в Kotlin-проектах с Dagger обычно связана с тем, что Dagger не может корректно обработать аннотации из-за особенностей работы kapt (Kotlin Annotation Processing Tool). В 90% случаев это происходит, когда вы используете нестатические методы в @Module или когда модуль объявлен как data class или object без правильных модификаторов.

В вашем примере модуль объявлен как обычный класс (не object и не abstract). Для Dagger это означает, что ему нужно создавать экземпляр модуля, что в Kotlin может вызвать конфликты с kapt. Dagger "видит" класс, но не может сгенерировать для него корректный код, так как Kotlin компилятор может изменить сигнатуру или добавить скрытые методы (например, component1() для data class, но у вас не data class — это хорошо).

Однако самая частая причина — отсутствие аннотации @JvmStatic на методах @Provides внутри модуля-объекта. Давайте посмотрим на исправленный код:

@Module
object NetworkModule {  // Используем object вместо class
    @Provides
    @Singleton
    @JvmStatic  // Обязательно для методов в object-модулях
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

Почему это работает?

  • object — это синглтон в Kotlin, и Dagger не нужно создавать его экземпляр, что снижает нагрузку на kapt.
  • @JvmStatic — говорит Kotlin сгенерировать статический метод для Java-совместимости. Dagger (написанный на Java) ожидает увидеть статические методы в модулях, объявленных как object или abstract.
  • Если ваш модуль должен иметь состояние, используйте abstract class вместо class.

Альтернативное решение (если не хотите object)

Можно оставить класс, но добавить конструктор без параметров и аннотацию @Module(includes = [...]):

@Module
class NetworkModule {
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

// В компоненте:
@Component(modules = [NetworkModule::class])
@Singleton
interface AppComponent { ... }

Но этот вариант менее надёжен — Dagger может снова выдать ошибку, если в проекте есть другие Kotlin-конструкции (например, inline-функции или свойства с backing field).

Дополнительные советы

  • Убедитесь, что у вас подключён kapt в build.gradle: id 'kotlin-kapt'.
  • Проверьте версии Dagger и Kotlin — они должны быть совместимы. Например, Dagger 2.48+ требует Kotlin 1.8+.
  • Если ошибка остаётся, попробуйте добавить @Module(includes = [...]) или использовать @Binds вместо @Provides для интерфейсов.
<<>>

Проблема с kapt и многомодульностью

Если вы используете многомодульный проект (например, feature-модули), ошибка Prefer to run the dagger processor over that class instead может возникать из-за того, что Dagger не может найти сгенерированный код в соседнем модуле. Решение — убедиться, что kapt настроен во всех модулях, где есть Dagger-аннотации, и что зависимость между модулями корректна.

// В build.gradle каждого модуля с Dagger:
plugins {
    id 'kotlin-kapt'
}
dependencies {
    implementation 'com.google.dagger:dagger:2.48'
    kapt 'com.google.dagger:dagger-compiler:2.48'
}

Также проверьте, не используете ли вы @Inject на конструкторе data class — это частая причина путаницы для Dagger. Если у вас есть data class с @Inject constructor, замените его на обычный класс или добавьте @JvmOverloads.

Ещё один трюк: иногда помогает очистка кеша kapt: ./gradlew clean и удаление папки .gradle в корне проекта.