Kotlin: установить аннотированную переменную lateinit с помощью отражения - PullRequest
1 голос
/ 10 июля 2020

Представьте, что я пытаюсь создать простую библиотеку для внедрения зависимостей. Его класс 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, но ведь должен быть более чистый способ, верно?

1 Ответ

2 голосов
/ 10 июля 2020

Если вы хотите разместить аннотацию на поле, вы можете использовать @field:Service.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...