Kotlin中Lambda注解传播机制及前置注解获取方法咨询
Kotlin 标注在Lambda上的注解获取方案
不需要实现javaagent或引入AOP能力,直接通过反射即可获取,核心是找对注解在字节码里的实际存储位置。
为什么直接查invoke()方法拿不到注解
Kotlin编译器处理Lambda上的注解时,不会把注解附加到Lambda实现类的invoke()执行方法上——invoke()仅负责承载Lambda的执行逻辑,和注解存储完全无关,所以查这个方法的注解永远拿不到结果。
具体实现步骤
- 首先确认你使用的注解,在声明时的
@Target配置包含AnnotationTarget.EXPRESSION,否则注解根本不会被编译保留到Lambda的字节码中,官方示例里的@Suspendable就满足这个要求。 - 拿到目标Lambda对应的实例的实际生成类,不要用
Function0/Function1这类公共函数接口的Class对象。 - 反射遍历这个类的所有声明方法,找到名为
$annotations的静态合成方法:这个方法无入参,返回值类型为Array<Annotation>,是Kotlin编译器专门用来存放Lambda上注解的位置。 - 强制开放这个方法的访问权限,静态调用它拿到的返回值,就是标注在这个Lambda上的所有注解。
可运行示例代码
对应官方给出的val f = @Suspendable { Fiber.sleep(10) }示例,获取注解的代码如下:
import co.paralleluniverse.fibers.Suspendable import java.lang.reflect.Modifier val f = @Suspendable { Fiber.sleep(10) } fun main() { val lambdaImplClass = f.javaClass // 查找编译器生成的注解存储方法 val annotationMethod = lambdaImplClass.declaredMethods.firstOrNull { method -> method.name == "\$annotations" && Modifier.isStatic(method.modifiers) && method.parameterCount == 0 && method.returnType == Array<Annotation>::class.java } val annotations = if (annotationMethod != null) { annotationMethod.isAccessible = true annotationMethod.invoke(null) as Array<Annotation> } else { emptyArray() } // 此处即可拿到@Suspendable注解实例 println(annotations.toList()) }
注意事项
- 如果Lambda被 inline 函数内联,编译后不会生成独立的Lambda实现类,自然无法通过反射获取注解,需要保留Lambda实例时可以给对应参数加
@NoInline注解避免被内联优化。 - 这个逻辑是Kotlin编译器原生的稳定字节码生成规则,不需要额外引入字节码增强、编译期插件之类的特殊依赖。
内容的提问来源于stack exchange,提问作者toolateitsme
相关产品推荐
相关产品推荐

