【问题标题】:Kotlin - How to get KClass<*> annotation parameter from annotation processorKotlin - 如何从注释处理器获取 KClass<*> 注释参数
【发布时间】:2019-10-18 09:35:19
【问题描述】:

我有以下注释:

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

我需要在我的注释处理器中获取ownerconsumer 的值。

我试过这种方法:

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 值。

所以这就是我现在卡住的地方,感谢任何帮助。 谢谢!

【问题讨论】:

    标签: java kotlin annotations


    【解决方案1】:

    让我们从第二种方法不起作用的原因开始:

    The annotation returned by this method could contain an element whose value is of type Class. This value cannot be returned directly: information necessary to locate and load a class (such as the class loader to use) is not available, and the class might not be loadable at all. Attempting to read a Class object by invoking the relevant method on the returned annotation will result in a MirroredTypeException, from which the corresponding TypeMirror may be extracted. Similarly, attempting to read a Class[]-valued element will result in a 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 }
    

    并为DataOwner 返回TypeMirror

    【讨论】:

    • 如果我们需要这个值的 KClass 而不是 TypeMirror 怎么办。有没有办法解决这个问题?谢谢
    • 可以尝试使用docs.oracle.com/en/java/javase/11/docs/api/java.compiler/javax/… 获取名称,然后从名称中使用KClass。您不应该这样做,如果该类不在标准库中,它肯定会失败(准确地说,不在编译器的类路径中,这根本不是您正在编译的类路径)。同样,因为那些 Classes 和 KClasses 还不存在。再说一遍:你不应该那样做。
    • 感谢您的回答。更具体地说,在我的用例中,即使使用非标准类 e.x: Intent 来自android,我也使用类型镜像。问题是,如果我在类型为kotlin.String 时执行此操作,则返回的镜像类型为java.lang.String,这应该是kotlin.String,因为我的库必须使用 kotlin。我怎样才能得到名字?使用 typeutils?还是元素工具?
    • 啊,那些只关心Java。我认为您可能只需要维护基于kotlinlang.org/docs/reference/java-interop.html#mapped-types 的类型映射,除非它在某个地方的 kotlin-reflect 中。
    • 非常感谢!非常感谢@alexey-romanov。我认为它可能是一个从 java 映射到 kotlin 的实用程序类,就像这里 github.com/Multifuchs/kmf/blob/master/kmf-kapt/bin/main/de/mf/… 一样,但似乎并非如此。
    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 2017-05-22
    相关资源
    最近更新 更多