1

I've created an annotation for properties and now I want to read it via reflection at runtime. In my opinion I'm doing everything right but there's no annotation.

Why isn't the annotation not available?

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
annotation class MyAnnotation

class MyClass(@MyAnnotation val attr: List<String>)

fun main(args: Array<String>) {
    var prop = MyClass::attr
    prop.annotations.forEach { println("prop.annotations -> " + it) }
    prop.javaClass.getAnnotations().forEach { println("prop.javaClass.getAnnotations -> " + it) }
    println("isAnnotationPresent -> ${prop.javaClass.isAnnotationPresent(MyAnnotation::class.java)}")
}

Output:
prop.javaClass.getAnnotations -> @kotlin.Metadata(xi=0, bv=[1, 0, 3], mv=[1, 1, 16], k=3, xs=, d1=[], d2=[], pn=) isAnnotationPresent -> false

Jayser
  • 371
  • 4
  • 15

2 Answers2

3

Instead of having the annotation target specified as @Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER), you can specify it as @Target(AnnotationTarget.FIELD) and access it as below:

@Target(AnnotationTarget.FIELD)
annotation class MyAnnotation

class MyClass(@MyAnnotation val attr: String)

fun main(args: Array<String>) {
    val prop = MyClass::attr
    println("Is MyAnnotation annotated - ${prop.javaField?.isAnnotationPresent(MyAnnotation::class.java)}")
    prop.javaField?.annotations?.forEach { println("Annotation present is - ${it.annotationClass.qualifiedName}") }
}

The output:

Is MyAnnotation annotated - true

Annotation present is - packageName.MyAnnotation

Community
  • 1
  • 1
Madhu Bhat
  • 13,559
  • 2
  • 38
  • 54
  • Does this help @Jayser ? – Madhu Bhat Dec 30 '19 at 18:00
  • I had to replaced javaField with javaClass but it didn't work. – Jayser Dec 31 '19 at 08:52
  • @Jayser no you shouldn't use `javaClass`, but use `javaField` as specified in my answer. The code snippet that is part of my answer works fine. Please try that. – Madhu Bhat Dec 31 '19 at 08:56
  • I use Kotlin 1.3.61 and I get an compile time error of "Unresolved reference: javaField" – Jayser Dec 31 '19 at 11:10
  • kotlin-reflect is also added to my maven dependencies. I don't why the javaField Property isn't available. – Jayser Dec 31 '19 at 11:16
  • @Jayser that might be an environment issue, as `javaField` is from kotlin-reflect itself. Can you try the solutions mentioned [here](https://stackoverflow.com/questions/31712046/kotlin-unresolved-reference-in-intellij/53063096)? – Madhu Bhat Dec 31 '19 at 13:49
1

As documented

If you don't specify a use-site target, the target is chosen according to the @Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:

  • param;

  • property;

  • field.

So in your case it's the parameter which is annotated, not the property. Depending on your requirements, you could work around it by checking both property and parameter annotations:

val param = MyClass::class.primaryConstructor.findParameterByName(prop.name)
val annotations = prop.annotations + (param?.annotations ?: listOf())
Community
  • 1
  • 1
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487