Imagine that I try to build simple dependency injection lib. Its Injector
class, when called on a specific class, should inject all properties annotated with @Service
annotation.
For example, given this client:
class ClientA {
@Service private lateinit var service1: Service1
@Service private lateinit var service2: Service2
private lateinit var service3: Service3
}
a call to injector.inject(ClientA())
should result in service1
and service2
being set (but not service3
). Let's assume that Injector
knows how to construct these objects.
My question is how to write the code that parses class' properties, checks their annotations and sets them in Kotlin?
Since I'm on Android, I tried to go through Java reflection:
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
}
The problem is that fieldAnnotations
is empty. Converting ClientA
's code to Java I see the following:
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() {
}
}
Looks like Kotlin compiler creates static methods to aggregate properties' annotations. With this info, I can write some ugly code to make it work using Java's reflection API, but there must be a cleaner way, right?
Aucun commentaire:
Enregistrer un commentaire