Обработка аннотаций Kotlin игнорирует элементы с похожими именами

Недавно я перевел большую часть своего проекта на kotlin. Теперь я столкнулся с несколькими необычными ошибками, которые, похоже, связаны с библиотеками аннотаций. Излишне говорить, что этого не произошло в Java.

Я опишу кейсы - один в Кинжале и один в Баттернайфе.

1. При наличии 2 методов @Provides в разных моделях с одинаковыми именами. Например, в файле «FooProvider.kt» есть метод «provideFooOrBar».

@Module
class FooProvider(private val view: FooActivity) {
    ... 
    @Provides @FooScope fun provideView() = view
    @Provides @FooScope fun provideFooOrBar() = Foo()
}

И иметь другой файл «BarProvider.kt» с тем же именем метода

@Module
class BarProvider(private val view: BarActivity) {
    ...
    @Provides @BarScope fun provideView() = view
    @Provides @BarScope fun provideFooOrBar() = Bar()
}

В этом случае Dagger не может сгенерировать некоторые фабричные библиотеки, и я получаю следующую ошибку компиляции: Error:(27, 32) error: cannot find symbol class FooProvider_ProvideFooOrBarFactory

Пример проекта, воспроизводящего проблему, можно найти по адресу https://github.com/maxandron/DaggerIssue325.

2. Это проблема при использовании Butterknife. При наличии двух аннотированных переменных @Bind в двух разных классах - одна из них просто не инициализируется во время выполнения без какой-либо ошибки компиляции!

Например, если у меня есть:

class FooActivity {
    @Bind(R.id.foo) lateinit var mFoo: View
}
class NotFooActivity {
    @Bind(R.id.not_foo) lateinit var mFoo: View
}

Тогда один из них (или оба?) просто не смогут инициализироваться без каких-либо ошибок. Вызывает исключение kotlin.UninitializedPropertyAccessException: lateinit property mFoo has not been initialized при доступе к полю.


Это что-то, что я делаю неправильно при настройке Kotlin, или это ошибка kotlin?

Заранее спасибо! Рон


person maxandron    schedule 25.02.2016    source источник
comment
Эти два вопроса кажутся мне не связанными, пожалуйста, не задавайте два разных вопроса в одном сообщении SO в следующий раз.   -  person Alexander Udalov    schedule 25.02.2016
comment
Я разместил их в том же вопросе, потому что они кажутся связанными. Я не думаю, что это ошибка кинжала или ножа для масла — я думаю, что это ошибка котлина. Я не пытаюсь найти решения ошибки - я их знаю, я хочу понять причину   -  person maxandron    schedule 25.02.2016
comment
Скорее всего, это две разные проблемы. Один для методов, а другой для того, где вы разместили аннотацию к свойству. Прочтите о целях использования аннотаций и посмотрите, поможет ли это решить вторую задачу kotlinlang.org/docs/reference/, а также, возможно, создание JvmField в зависимости от того, что хочет Butterknife kotlinlang.org/docs/reference/   -  person Jayson Minard    schedule 25.02.2016
comment
Вы смотрели на KnotterKnife? github.com/JakeWharton/kotteknife, который похож на Butterknife, но написан для Kotlin.   -  person Jayson Minard    schedule 25.02.2016
comment
Также существуют специальные библиотеки внедрения зависимостей Kotlin, которые понимают Kotlin лучше, чем что-то из Java. Например, Java не может видеть обнуляемость и не может создавать объект Kotlin при использовании параметров по умолчанию (если только вы не используете @JvmOverloads), не может видеть имена параметров. Так что примитивная система пытается использовать более продвинутую, не понимая ее. Injekt и Kodein могут быть полезны.   -  person Jayson Minard    schedule 25.02.2016
comment
так что, как говорит @AlexanderUdalov, у вас, вероятно, есть две разные проблемы в одном вопросе SO.   -  person Jayson Minard    schedule 25.02.2016
comment
Для вашей первой проблемы кажется странным, что это проблема Kotlin. Это обычные классы с обычными методами, и байтовый код будет идентичен Java, делающему то же самое. Должны ли классы быть расширяемыми? (т.е. open class) вместо окончательного? Я бы подумал, что это не сработает в Java, именно в этом случае, потому что разницы нет. Ваша проблема со свойствами МОЖЕТ быть связана с целью аннотации, но я думаю, что в этом другом случае вы или ошибка кинжала   -  person Jayson Minard    schedule 25.02.2016
comment
Ясно... должен ли я тогда как-то разделить этот вопрос на два? Просто кажется маловероятным столкнуться с двумя проблемами, которые кажутся связанными (обе из-за похожих имен переменных/методов) одна за другой. Кроме того, я попытался воспроизвести первую проблему в Java и не увенчался успехом, это определенно проблема только для котлина.   -  person maxandron    schedule 25.02.2016
comment
Я не понимаю, как они могут быть связаны, сейчас проверяю ваш тестовый проект.   -  person Jayson Minard    schedule 25.02.2016
comment
что такое эквивалент Java, есть ли он в вашем тестовом проекте?   -  person Jayson Minard    schedule 25.02.2016
comment
Да, вы можете найти его в этом коммите: github.com/maxandron/DaggerIssue325/tree/ Спасибо за помощь, Джейсон!   -  person maxandron    schedule 25.02.2016
comment
Проблема может быть в порядке компиляции, вы используете Kapt?   -  person Jayson Minard    schedule 25.02.2016
comment
ваши файлы проекта непригодны для использования, по какой-то причине они имеют жестко запрограммированные пути к модулям.   -  person Jayson Minard    schedule 25.02.2016
comment
Я. попробую еще раз зафиксировать   -  person maxandron    schedule 25.02.2016
comment
У вас есть исходные наборы для src/main/kotlin в вашей градации, но затем вы поместили свой исходный код в src/main/java, это проблема?   -  person Jayson Minard    schedule 25.02.2016
comment
Нет, не должно быть - Он просто добавляет исходники. В моем другом проекте у меня есть исходники в /java и некоторые в /kotlin.   -  person maxandron    schedule 25.02.2016
comment
Итак, ваша ошибка связана с сборкой командной строки Gradle или сборкой IDE?   -  person Jayson Minard    schedule 25.02.2016
comment
из сборки IDE (студия Android)   -  person maxandron    schedule 25.02.2016
comment
Я думаю, что удалил из репозитория все файлы, которые могут содержать жестко закодированные пути.   -  person maxandron    schedule 25.02.2016
comment
Я не могу заставить студию Android загрузить ваш проект достаточно хорошо, чтобы что-то сделать, я думаю, что человек с Android может помочь больше, особенно потому, что он больше использует Kapt и связанные с ним инструменты. Возможно, ошибка где-то в обработке аннотаций, в том, как искажаются имена и т. д. Вам нужно сузить круг вопросов, возможно, указать ошибку в YouTrack (youtrack.jetbrains.com) или спросить людей на канале #android на Kotlin. slack, так как они могли столкнуться с этим или расскажут вам, что они используют вместо этого. kotlinlang.org/community.html   -  person Jayson Minard    schedule 25.02.2016


Ответы (3)


У меня была эта проблема, поэтому я начал исследовать ее, потому что Kapt проверяет только имя метода при их сравнении, , и они добавляются в set, поэтому дубликаты не допускаются. То же самое происходит и с аннотированными полями, поэтому в настоящее время у вас может быть одно имя метода/поля для каждой аннотации.

Я добавил имя класса в метод equals, и теперь аннотации обрабатывались правильно, но тесты сломались, и я не знаю, как они работают, поэтому я надеюсь, что кто-то знает, как это исправить.

person inorichi    schedule 20.03.2016
comment
Хорошая находка! Я вижу здесь, что поля тоже только проверено по имени, что объясняет масляный нож. В любом случае, они ушли от проблемы и решают ее - я отпишусь здесь, когда она будет решена - person maxandron; 21.03.2016
comment
Также означает, что я был прав, опубликовав эти две проблемы в одних и тех же вопросах (а быть правым всегда хорошо :)) - person maxandron; 21.03.2016
comment
Я только что нашел уже открытый запрос на вытягивание github.com/JetBrains/kotlin/pull/822 - person inorichi; 25.03.2016

Оказалось баг с kapt. Я опубликовал проблему в системе отслеживания ошибок Kotlin, и теперь она помечена как исправленная.

Это решение было объединено

Должно быть решено в Kotlin версии 1.0.2

person maxandron    schedule 31.03.2016

Итак, чтобы как-то ответить на проблему kotlin.UninitializedPropertyAccessException: lateinit, я столкнулся с тем же самым в моем проекте. То, что я сделал, что «решило проблему» для меня, заключалось в том, чтобы удалить Butterknife из класса-нарушителя, в данном случае это был просто viewHolder для моего нового расширяемого RecyclerView, а затем снова запустить приложение.

Запустив приложение, после переключения всех моих @Bind(R.id.my_view_id) на "старую школу" findViewById(R.id.my_view_id) as MyViewType сработало, но впоследствии я переключил тот же класс назад на Butterknife, и UninitializedPropertyAccessException исчез, и кажется, что он победил' Если вы не вернетесь, если что-то в классе не изменится, вам придется повторить этот процесс еще раз.

Я подозреваю, что это как-то связано с тем, что Kotlin не поддерживает инкрементную компиляцию, и каким-то образом из-за изменения автоматически сгенерированного кода он был вынужден перекомпилировать. Но я мог бы быть далеко здесь, просто решил поделиться своим опытом.

person Derek    schedule 28.02.2016
comment
Спасибо за ваши усилия, очевидно, у меня всегда есть возможность отключить библиотеки, которые я использовал раньше. Но я не хочу. Суть использования Kotlin заключается в полной совместимости с Java. В любом случае, после исследования и публикации ошибки на трекере. Это определенно ошибка с kapt. Я обновлю здесь, когда это будет исправлено. Прямо сейчас я переключаю Butterknife на плагин «kotlin android extensions». - person maxandron; 29.02.2016