首页 文章

使用反射读取Kotlin函数注释值?

提问于
浏览
2

给定这样的接口方法(Android Retrofit),如何在运行时从Kotlin代码中读取注释参数中指定的URL路径?

ApiDefinition接口:

@GET("/api/somepath/objects/")
fun getObjects(...)

读取注释值:

val method = ApiDefinition::getObjects.javaMethod
val verb = method!!.annotations[0].annotationClass.simpleName ?: ""
// verb contains "GET" as expected
// But how to get the path specified in the annotation?
val path = method!!.annotations[0].????????

更新1

谢谢你的回答 . 我仍在苦苦挣扎,因为我无法看到用于执行以下操作的类型:

val apiMethod = ApiDefinition::getObjects

....然后将该函数引用传递给这样的方法(它被重用)

private fun getHttpPathFromAnnotation(method: Method?) : String {
    val a = method!!.annotations[0].message
}

IntelliJ IDE建议我使用KFunction5 <>作为函数参数类型(它在我看来并不存在)并且似乎要求我也为该方法指定所有参数类型,这使得通用调用得到注释属性不可能 . 是不是Kotlin等同于“方法”?,这种类型会接受任何方法?我尝试了KFunction,没有成功 .

更新2

谢谢你澄清一些事情 . 我已经到了这一步:

ApiDefinition(改造界面)

@GET(API_ENDPOINT_LOCATIONS)
fun getLocations(@Header(API_HEADER_TIMESTAMP) timestamp: String,
                 @Header(API_HEADER_SIGNATURE) encryptedSignature: String,
                 @Header(API_HEADER_TOKEN) token: String,
                 @Header(API_HEADER_USERNAME) username: String
                 ): Call<List<Location>>

检索注释参数的方法:

private fun <T> getHttpPathFromAnnotation(method: KFunction<T>) : String {
    return method.annotations.filterIsInstance<GET>().get(0).value
}

调用以获取特定方法的path参数:

val path = getHttpPathFromAnnotation<ApiDefinition>(ApiDefinition::getLocations as KFunction<ApiDefinition>)

隐式转换似乎是必要的,或者类型参数要求我提供KFunction5类型 .

这段代码有效,但它有GET注释硬编码,有没有办法让它更通用?我怀疑我可能需要寻找GET,POST和PUT并返回第一场比赛 .

1 回答

  • 3

    直接使用Kotlin KFunction而不是 javaMethod (无论如何你都在使用Kotlin!)和findAnnotation用于简洁,惯用的代码 .

    如果注释不是第一个, annotations[0] 可能会破坏,这也会有效 .

    val method = ApiDefinition::getObjects
    
    val annotation = method.findAnnotation<GET>() // Will be null if it doesn't exist
    
    val path = annotation?.path
    

    基本上所有 findAnnotation 都是回归

    annotations.filterIsInstance<T>().firstOrNull()
    

相关问题