I have the following annotation:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Model(
val owner: KClass<*>,
val consumer: KClass<*>
)
@Model(DataOwner::class, DataConsumer::class)
interface Student {
val name: String
val group: Group
}
I need to get the value of owner and consumer in my annotation processor.
I've tried this approach:
private inline fun <reified T> findAnnotationValue(
element: Element,
annotationClass: KClass<*>,
valueName: String
): T? {
return element.annotationMirrors.map {
it to it.annotationType.asElement() as TypeElement
}.firstOrNull { (_, element) ->
element.qualifiedName.contentEquals(annotationClass.qualifiedName)
}?.let { (mirror, _) ->
extractValue(mirror, valueName)
}
}
private inline fun <reified T> extractValue(
annotationMirror: AnnotationMirror,
valueName: String
): T? {
return annotationMirror.elementValues.toList()
.firstOrNull { (key, _) ->
key.simpleName.contentEquals(valueName)
}?.let { (_, value) ->
value.value as T
}
}
val ownerClass: KClass<*> = findAnnotationValue(
element,
Model::class,
"owner"
)
But it gave me this error:
e: [kapt] An exception occurred: java.lang.ClassCastException: com.sun.tools.javac.code.Type$ClassType cannot be cast to kotlin.reflect.KClass
I also tried this:
val ownerClass: KClass<*> = element.getAnnotation(Model::class.java).owner
But it gave me this error:
e: [kapt] An exception occurred: javax.lang.model.type.MirroredTypeException: Attempt to access Class object for TypeMirror inc.ahmedmourad.systems.tutors.domain.model.DataOwner
inc.ahmedmourad.systems.tutors.domain.model.DataOwner is the owner value passed to the annotation.
So this's where i'm stuck right now, any help is appreciated. Thank you!
If you are using KSP then the solution can look something like this:
Using the experimental APIs and assuming the KClass you reference in the annotation is available:
resolver.getSymbolsWithAnnotation("com.example.Model")
.map {
val consumerType = try {
it.getAnnotationsByType(Model::class).first().consumer
null
} catch (e: KSTypeNotPresentException) {
e.ksType
}
val consumerDeclaration = consumerType!!.declaration as KSClassDeclaration // etc
}
If you can't do this, then maintaining a KSP view of the annotation is more flexible:
resolver.getSymbolsWithAnnotation("com.example.Model")
.map { ksAnnotated ->
val args = ksAnnotated.annotations.first {
it.shortName.asString() == "Model" && it.annotationType.resolve().declaration.qualifiedName?.asString() == "com.example.Model"
}.arguments
val consumerType = args.first { it.name?.asString() == "owner" }.value as KSType
val consumerDeclaration = consumerType.declaration as KSClassDeclaration // etc
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With