Представьте, что я пытаюсь создать простую библиотеку для внедрения зависимостей. Его класс Injector
при вызове из определенного класса c должен вводить все свойства, аннотированные аннотацией @Service
.
Например, для этого клиента:
class ClientA {
@Service private lateinit var service1: Service1
@Service private lateinit var service2: Service2
private lateinit var service3: Service3
}
a вызов injector.inject(ClientA())
должен привести к установке service1
и service2
(но не service3
). Предположим, что Injector
знает, как создавать эти объекты.
Мой вопрос в том, как написать код, который анализирует свойства класса, проверяет их аннотации и устанавливает их в Kotlin?
Так как я нахожусь на Android, я пробовал go через Java отражение:
fun inject(client: Any) {
val clientClass = client::class.java
val fields = clientClass.declaredFields
for (field in fields) {
if (isAnnotatedForInjection(field)) {
injectField(client, field)
}
}
}
private fun isAnnotatedForInjection(field: Field): Boolean {
val fieldAnnotations = field.annotations
for (annotation in fieldAnnotations) {
if (annotation is Service) {
return true
}
}
return false
}
Проблема в том, что fieldAnnotations
пусто. Конвертируя код ClientA
в Java, я вижу следующее:
public final class ClientA {
private Service1 service1;
private Service2 service2;
private Service3 service3;
/** @deprecated */
// $FF: synthetic method
@Service
private static void service1$annotations() {
}
/** @deprecated */
// $FF: synthetic method
@Service
private static void service2$annotations() {
}
}
Похоже, что Kotlin компилятор создает методы c stati для агрегирования аннотаций свойств. Имея эту информацию, я могу написать какой-нибудь уродливый код, чтобы заставить его работать, используя API отражения Java, но ведь должен быть более чистый способ, верно?