Есть ли какой-нибудь способ «скрыть» функцию Kotlin от модифицированного процессора аннотаций?

#java #kotlin #retrofit #kotlin-coroutines #annotation-processing

#java #kotlin #модернизация #kotlin-сопрограммы #обработка аннотаций

Вопрос:

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

 interface ApiInterface : Context.Element {
    @GET(Urls.url)
    suspend fun getSomeData(): Data
}

interface Context.Element {
    operator fun plus(context: Context): Context
}
 

Я пытаюсь реализовать Context реализацию аналогично Kotlin CoroutineContext . Поскольку я пытаюсь добавить свой модифицированный http-интерфейс в качестве Context.Element , он в конечном итоге наследует некоторые другие функции. Код компилируется и работает нормально, пока я не вызову функцию из моего экземпляра ApiInterface, которая наследуется от Context.Element , следовательно, не имеет какой-либо @GET @POST или какой-либо модифицированной аннотации.

Если я выполню следующий код:

 val context = ApiInterfaceImpl()
context   DifferentApiInterfaceImpl()
 

Я получаю Exception in thread "main" java.lang.IllegalArgumentException: HTTP method annotation is required (e.g., @GET, @POST, etc.). for method Context.plus .

Я считаю, что если я смогу заставить модифицированный процессор аннотаций пропустить функции, унаследованные от Context.Element этой проблемы, проблема будет решена. Есть ли какой-нибудь способ для этого? Есть ли @Transient подобные аннотации для функций? Я пытался использовать @JvmSynthetic , но безуспешно.

Ответ №1:

Проблема здесь не в процессоре аннотаций, а в том, как работает Retrofit. Он не генерирует класс реализации, но создает прокси-объект во время выполнения, и этот прокси-объект обрабатывает все вызовы методов и направляет их в соответствующий обработчик. Очевидно, что он не может обрабатывать несервисный метод. Также неясно, как вы могли бы предоставить реализацию для этого неаннотизированного метода. Поэтому я бы сказал, что в настоящее время это невозможно.

Редактировать: поскольку вы используете метод по умолчанию в интерфейсе для обеспечения реализации, он, как правило, должен работать, я полагаю, потому Retrofit что обрабатывает методы по умолчанию отдельно. Проблема здесь может заключаться в том, что Retrofit известно только о методах java по умолчанию, и по умолчанию kotlin их не использует (для совместимости с java 7 и ниже). Итак, если вы заставите компилятор генерировать метод java по умолчанию, он должен работать. Пожалуйста, ознакомьтесь с этим сообщением для получения подробной информации.

Комментарии:

1. Я понимаю. Спасибо, еда, чтобы знать… Я всегда думал, что это поддерживается сгенерированным классом реализации. Кстати, способ, которым я предоставил реализацию для метода без аннотаций (the plus() ), заключался в том, что в интерфейсе была реализована реализация по умолчанию. Проблема невозможности заставить модифицированный интерфейс расширить мой Context интерфейс заключается в том, что я не могу иметь то же Key самое для ApiInterface реализации, присутствующей в моем Context . Пытаюсь найти хороший способ сделать это. Еще раз спасибо за вашу помощь!

2. @admqueiroga Пожалуйста, ознакомьтесь с обновленным ответом.

3. Я думаю, это именно то, что мне нужно. Пытаюсь добавить -Xjvm-default=enable в проект Kotlin, но теперь мне приходится иметь дело с Error: Could not create the Java Virtual Machine. , я думаю, как только я выясню, куда добавить аргумент, он будет работать. Прямо сейчас я добавляю like kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=enable") , но это нарушает работу JVM. Еще раз спасибо за помощь @esentsov! Действительно ценю!

4. Если я не установил kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=enable") , IDE отображает ошибку везде, где я использую @JvmDefault . Когда я устанавливаю этот флаг, ошибки исчезают, но JVM не может быть создан из-за Unrecognized option: -Xjvm-default . Кстати, используя Gradle

5. Вы также установили jvmTarget = "1.8" для kotlin и sourceCompatibility , targetCompatibility чтобы JavaVersion.VERSION_1_8 ?