Reputation: 10320
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?
Upvotes: 3
Views: 686
Reputation: 1
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
The target @property grants the annotation won't end up over a getter but over the property itself, and makes it readable to the 'memberProperties' KClass property. Thereby iterate through the class properties, find the property, and check if it has the annotation by using the 'hasAnnotation<FooBar>()
' KProperty1 method. In order to get the annotation object, use 'findAnnotation<FooBar>()
' KProperty1 method.
Upvotes: 0
Reputation: 21
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
Upvotes: 2