mardi 18 décembre 2018

How to list (java) annotations on Kotlin data class fields?

I am using Firestore's Java-based annotation for marking fields and methods for mapping document fields to Java class elements:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface PropertyName {
  String value();
}

I am using it on a field in a Kotlin data class, which compiles fine:

data class MyDataClass(
    @PropertyName("z") val x: Int
)

In IntelliJ and Android Studio, I can see it show up in the decompiled class dump:

public final data class MyDataClass public constructor(x: kotlin.Int) {
    @field:com.google.cloud.firestore.annotation.PropertyName public final val x: kotlin.Int /* compiled code */

    public final operator fun component1(): kotlin.Int { /* compiled code */ }
}

My impression at this point is that this annotation should be discoverable somehow via Kotlin reflection. As far as I can tell, it is not. I've tried iterating the annotations on:

  1. Each Kotlin data class constructor fields
  2. Each Kotlin field
  3. Each Kotlin function
  4. Each Java constructor
  5. Each Java field
  6. Each Java method

It just does not show up anywhere.

The moment I change the usage of the annotation like this (note the target specifier "get" now):

data class MyDataClass(
    @get:PropertyName("z") val x: Int
)

The annotation now shows up in the generated getter of the Java class object. This is at least workable in practice, but I'm curious why Kotlin lets me compile the annotation in as a field-targeted annotation, but doesn't allow me to get it back out at runtime (unless I'm missing something in the kotlin-reflect APIs?).

If I use this Kotlin-based annotation instead:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class PropertyName(val value: String)

With this, the annotation shows up at runtime on the Kotlin field. This is curious because Java's ElementType.FIELD simply does not seem to map perfectly to Kotlin's AnnotationTarget.FIELD.

(Incidentally, if I change this to AnnotationTarget.LOCAL_VARIABLE, I can also discover this annotation in the data class constructor parameter.)

This feels like a bug to me, but I'm open to seeing if I just did something wrong here. Or maybe this is just not supported. I'm using Kotlin 1.3.11. Same behavior on JVM and Android.





Aucun commentaire:

Enregistrer un commentaire