在Kotlin中创建注解示例

0pizxfdo  于 2023-04-21  发布在  Kotlin
关注(0)|答案(3)|浏览(152)

我有一个用Java编写的框架,使用反射,获取注解上的字段并根据它们做出一些决定。在某些时候,我还可以创建注解的ad-hoc示例并自己设置字段。这部分看起来像这样:

public @interface ThirdPartyAnnotation{
    String foo();
}

class MyApp{
    ThirdPartyAnnotation getInstanceOfAnnotation(final String foo)
        {
            ThirdPartyAnnotation annotation = new ThirdPartyAnnotation()
            {
                @Override
                public String foo()
                {
                    return foo;
                }

            }; 
            return annotation;
        }
}

现在我正在尝试在Kotlin中做同样的事情。请记住,注解是在第三方jar中的。无论如何,以下是我在Kotlin中的尝试:

class MyApp{
               fun getAnnotationInstance(fooString:String):ThirdPartyAnnotation{
                    return ThirdPartyAnnotation(){
                        override fun foo=fooString
                }
    }

但是编译器会抱怨:无法示例化注解类
所以问题是:我应该如何在Kotlin中做到这一点?

h79rfbju

h79rfbju1#

你可以使用Kotlinreflection:

val annotation = ThirdPartyAnnotation::class.constructors.first().call("fooValue")

在annotation有无参数构造函数的情况下(例如,每个annotation字段都有一个默认值),您可以使用以下方法:

annotation class SomeAnnotation(
        val someField: Boolean = false,
)
val annotation = SomeAnnotation::class.createInstance()
8zzbczxx

8zzbczxx2#

这是我可能已经找到的解决方案,但对我来说感觉像是一个黑客,我更希望能够在语言中解决它。无论如何,值得的是,它是这样的:

class MyApp {
    fun getInstanceOfAnnotation(foo: String): ThirdPartyAnnotation {
        val annotationListener = object : InvocationHandler {
            override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
                return when (method?.name) {
                    "foo" -> foo
                    else -> FindBy::class.java
                }
            }
        }
        return Proxy.newProxyInstance(ThirdPartyAnnotation::class.java.classLoader, arrayOf(ThirdPartyAnnotation::class.java), annotationListener) as ThirdPartyAnnotation
    }
}
tpgth1q7

tpgth1q73#

从Kotlin1.6开始,这应该是可能的(参见KEEP
问题KT-45395
例如:

annotation class InfoMarker(val info: String)

fun processInfo(marker: InfoMarker) = ...

fun main(args: Array<String>) {
    if (args.size != 0)
        processInfo(getAnnotationReflective(args))
    else
        processInfo(InfoMarker("default"))
}

但是,如果您不幸处于较低的语言级别,则需要使用反射方法,如answered by Клаус Шварц

@get:JvmName("k")
    val kind: Int = 1,

那么反射调用(例如Metadata::class.constructors.first().call(...))将失败,返回一个java.lang.NoSuchMethodException: kotlin.Metadata.kind(),那么您需要使用代理方式(Proxy.newProxyInstance)作为answered by Claudiu Dumitrescu,/claudiu-dumitrescu),并且您可能还需要处理注解声明的默认值

相关问题