Kotlin - Как получить параметр аннотации KClass <*> из процессора аннотаций - PullRequest
0 голосов
/ 18 октября 2019

У меня есть следующая аннотация:

@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
}

Мне нужно получить значения owner и consumer в моем процессоре аннотаций.

Я пробовал этот подход:

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"
)

Но это дало мне эту ошибку:

e: [kapt] An exception occurred: java.lang.ClassCastException: com.sun.tools.javac.code.Type$ClassType cannot be cast to kotlin.reflect.KClass

Я также попробовал это:

val ownerClass: KClass<*> = element.getAnnotation(Model::class.java).owner

Но это дало мне эту ошибку:

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 - это значение owner, переданное аннотации.

Так что именно здесь я застрял прямо сейчас, любая помощь приветствуется. Спасибо!

1 Ответ

1 голос
/ 18 октября 2019

Начнем с причины, по которой второй подход не работает:

Аннотация, возвращаемая этим методом, может содержать элемент, значение которого имеет тип Class. Это значение не может быть возвращено напрямую: информация, необходимая для определения местоположения и загрузки класса (например, используемого загрузчика классов), недоступна, и класс может вообще не загружаться. Попытка прочитать объект Class путем вызовасоответствующий метод в возвращенной аннотации приведет к исключению MirroredTypeException, из которого может быть извлечено соответствующее TypeMirror. Аналогичным образом, попытка прочитать элемент с классом [] приведет к исключению MirroredTypesException.

, что, очевидно, также относится к KClass.

Так что для классов в аннотациях вы можете получить только TypeMirror (реализовано в этом случае Type.ClassType, но это внутренняя деталь, которую вы не должныположиться) а не KClass. Либо при первом подходе, либо

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
}

, который может использоваться как

element.getAnnotationClassValue<Model> { owner }

и возвращает TypeMirror для DataOwner.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...