Kotlin反射调用伴生对象方法报错:参数不匹配问题求助
解决Kotlin伴生对象反射调用的参数不足异常
问题背景
用ClassGraph扫描带@OnStartup注解的Kotlin伴生对象方法,启动时调用这些方法通知中心类,结果抛出异常:
Exception in thread "main" java.lang.IllegalArgumentException: Callable expects 1 arguments, but 0 were provided
推测需要传入伴生对象实例,但不知道怎么获取。
问题原因
Kotlin伴生对象在JVM上其实是宿主类的一个内部单例类,它的方法默认是这个单例类的成员方法,而非宿主类的静态方法。所以通过kotlinFunction拿到的KFunction调用时,必须传入伴生对象的实例作为第一个参数,否则就会报参数不足。
两种解决思路
思路一:给方法加@JvmStatic注解
直接给伴生对象里的@OnStartup方法加上@JvmStatic,让它变成JVM层面的静态方法,这样调用时不需要传任何参数。
修改后的SomeClass:
data class SomeClass(val name: String) { companion object { @OnStartup @JvmStatic // 新增注解 fun onStartup() { // 在启动时通知相关方本类的存在 } } }
原有的main和findStartupMethods代码不用改,直接运行即可。
思路二:手动获取伴生对象实例并传入
如果没法修改目标类的代码,就通过反射获取伴生对象的单例实例,调用方法时把它传进去。
修改后的核心代码:
fun main() { val scanResult = ClassGraph().enableAllInfo().acceptPackages("com.test").scan() scanResult .getClassesWithMethodAnnotation(OnStartup::class.java.name) .flatMap { getStartupMethodWithCompanion(it) } .forEach { (func, companionInstance) -> func.call(companionInstance) } } private fun getStartupMethodWithCompanion(classInfo: ClassInfo): List<Pair<KFunction<*>, Any>> { return classInfo.methodInfo.filter { it.hasAnnotation(OnStartup::class.java) } .mapNotNull { method -> val kFunc = method.loadClassAndGetMethod().kotlinFunction ?: return@mapNotNull null val hostKClass = classInfo.loadClass().kotlin // 获取伴生对象实例 val companion = hostKClass.companionObjectInstance ?: return@mapNotNull null kFunc to companion } }
这里通过hostKClass.companionObjectInstance拿到伴生对象的单例,然后作为参数传给KFunction.call()。
注意点
- 如果伴生对象是
private的,companionObjectInstance会返回null,要确保伴生对象是公共访问权限(默认就是public)。 - 思路一适合你能修改目标类的场景,简单直接;思路二更灵活,不用动目标类,适合扫描第三方类的情况。
内容的提问来源于stack exchange,提问作者delimiter
相关产品推荐
相关产品推荐

