2

I am creating a Kotlin compiler plugin in which I need to check if a property of a data class has an annotation:

data class User(
     @MyAnnotation
     val name: String
)

I override DelegatingClassBuilder.newField in the following way:

internal class MyClassBuilder(
    delegateBuilder: ClassBuilder
) : DelegatingClassBuilder(delegateBuilder) {
    override fun newField(
        origin: JvmDeclarationOrigin,
        access: Int,
        name: String,
        desc: String,
        signature: String?,
        value: Any?
    ): FieldVisitor {
        val visitor = super.newField(origin, access, name, desc, signature, value)
        val descriptor = origin.descriptor as? PropertyDescriptor ?: return visitor
        if (descriptor.annotations.hasAnnotation(FqName("com.example.MyAnnotation"))) {
            // I never get here
        }
        return visitor
    }
}

Problem: No matter if my property is annotated or not descriptor.annotations would not contain my annotation. If I change the annotations use target to anything else I still don't get the annotation.

At the same time, if I annotate a function and override newMethod, I can get annotations of of this function with pretty similar code.

Question: How to get annotations of a property in a data class?

Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148

2 Answers2

2

I guess my answer won't help you, but for anyone with a future problem. For field annotations without a Target the compiler will generate a function that has the annotation. So,

data class User(@MyAnnotation val name: String)

will compile to the following functions:

  • getName
  • getName$annotations
  • ...

As the name suggests, the annotation @MyAnnotation is located in getName$annotations.

You can avoid this by specifying a Target:

data class User(@field:MyAnnotation val name: String)

With the target, you can reference it directly via newField function; otherwise you have to access it via the newMethod function and extract the field. If you develop a plugin for end-user you probably should implement both methods, as the end-user might(not) add a target

MrGewurz
  • 21
  • 2
0

Try this:

myObject::class
    .memberProperties
    .forEach {
        if (it.hasAnnotation<FooBar>()) {
             val annotation = it.findAnnotation<FooBar>() 
             // doYourStuff()
        }
            

and in the data class:

@property:FooBar
val myField: Any