Kotlin:使用反射设置带注释的lateinit变量
想象一下,我试图构建简单的依赖项注入库。它的Kotlin:使用反射设置带注释的lateinit变量,kotlin,reflection,annotations,Kotlin,Reflection,Annotations,想象一下,我试图构建简单的依赖项注入库。它的Injector类在对特定类调用时,应该注入用@Service注释注释的所有属性 例如,给定此客户端: class ClientA { @Service private lateinit var service1: Service1 @Service private lateinit var service2: Service2 private lateinit var service3: Service3 } 调用injec
Injector
类在对特定类调用时,应该注入用@Service
注释注释的所有属性
例如,给定此客户端:
class ClientA {
@Service private lateinit var service1: Service1
@Service private lateinit var service2: Service2
private lateinit var service3: Service3
}
调用injector.inject(ClientA())
应导致设置service1
和service2
(而不是service3
)。让我们假设Injector
知道如何构造这些对象
我的问题是如何编写代码来解析类的属性、检查它们的注释并在Kotlin中设置它们
因为我使用的是Android,所以我尝试过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编译器创建了静态方法来聚合属性的注释。有了这些信息,我可以编写一些难看的代码来使用Java的反射API使其工作,但必须有一种更干净的方法,对吗?如果您想在字段上放置注释,可以使用
@field:Service
它是用于运行时还是编译时操作?您尝试过@field:Service
?@EpicPandaForce,它可以工作。谢谢把它贴出来作为答案,这样我就可以接受了。现在对我来说已经足够好了,但是在Kotlin中检查运行时注释难道没有更好的选择吗?一些“Kotlin-ish”?有Kotlin-Reflect,但它很大,我没有使用过,所以我现在对它了解得不够。我确信Dagger做了一些事情,消除了在对象
中使用@JvmStatic的需要,因此可能会有类似的更新,不再需要@field:
。我想知道他们是否只是检查两者……这里的要点是Kotlin为每个属性生成一个字段和访问器方法,默认情况下注释应用于后者@字段:
改变了这一点。细节。(顺便说一句,反射是一个经常被滥用的工具;在我看来,关于它的大多数问题可能都应该使用其他工具来代替。依赖注入是它非常适合的罕见的事情之一!)