Search code examples
reflectionkotlinannotations

Finding field annotations using obj::class.declaredMemberProperties


In the following test, the field id of class TestData is marked with the annotation Foo. Why is the output of .annotations and .findAnnotation<Foo>() empty though?

How can check if a field is annotated by a certain annotation?

(This is not the same question as How to list field annotations in Kotlin? where the asker forgot to change the retention to RUNTIME)

import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.findAnnotation
import kotlin.test.Test

class MissingAnnotationTest {

    @Target(AnnotationTarget.FIELD)
    @Retention(AnnotationRetention.RUNTIME)
    annotation class Foo

    data class TestData(@field:Foo val id: Int)

    @Test
    fun test() {
        val obj = TestData(123)
        val idProp = obj::class.declaredMemberProperties.first { it.name == "id" }
        println("1 name: " + idProp) // "val ...TestData.id: kotlin.Int"
        println("1 annotations: " + idProp.annotations) // [] - but why?
        println("1 found @Foo: " + idProp.findAnnotation<Foo>()) // null - but why?
    }

}

Solution

  • I got a hint in the Kotlin discussion group and can now answer it myself:

    A Kotlin "property" is compiled to a backing field and its getter/setter functions. If the target FIELD and not PROPERTY is used, the annotation is applied to the backing field. Pure backing fields do not exist in Kotlin though, therfore one has to access them via .javaField:

    val idField = obj::class.memberProperties.first { it.name == "id" }.javaField!!
    assertNotNull(idField.getAnnotation(Foo::class.java))