#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.
, я думаю, как только я выясню, куда добавить аргумент, он будет работать. Прямо сейчас я добавляю likekotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=enable")
, но это нарушает работу JVM. Еще раз спасибо за помощь @esentsov! Действительно ценю!4. Если я не установил
kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=enable")
, IDE отображает ошибку везде, где я использую@JvmDefault
. Когда я устанавливаю этот флаг, ошибки исчезают, но JVM не может быть создан из-заUnrecognized option: -Xjvm-default
. Кстати, используя Gradle5. Вы также установили
jvmTarget = "1.8"
для kotlin иsourceCompatibility
,targetCompatibility
чтобыJavaVersion.VERSION_1_8
?