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!
Let's start with the reason the second approach doesn't work:
which obviously applies to KClass
as well.
So for classes in annotations you can only get a TypeMirror
(implemented in this case by Type.ClassType
, but that's an internal detail you shouldn't rely on) and not a KClass
. Either by the first approach or
inline fun <reified T : Annotation> Element.getAnnotationClassValue(f: T.() -> KClass<*>) = try {
getAnnotation(T::class.java).f()
throw Exception("Expected to get a MirroredTypeException")
} catch (e: MirroredTypeException) {
e.typeMirror
}
which can be used as
element.getAnnotationClassValue<Model> { owner }
and returns the TypeMirror
for DataOwner
.