Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an annotation instance in Kotlin

Tags:

kotlin

I have a framework written in Java that, using reflection, get the fields on an annotation and make some decisions based on them. At some point I am also able to create an ad-hoc instance of the annotation and set the fields myself. This part looks something like this:

public @interface ThirdPartyAnnotation{
    String foo();
}

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

            }; 
            return annotation;
        }
}

Now I am trying to do the exact thing in Kotlin. Bear in mind that the annotation is in a third party jar. Anyway, here is how I tried it in Kotlin:

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

But the compiler complains about: Annotation class cannot be instantiated

So the question is: how should I do this in Kotlin?

like image 241
Claudiu Dumitrescu Avatar asked Nov 13 '15 10:11

Claudiu Dumitrescu


2 Answers

You can do this with Kotlin reflection:

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

In the case of annotation having no-arg constructor (e.g. each annotation field has a default value), you can use following approach:

annotation class SomeAnnotation(
        val someField: Boolean = false,
)
val annotation = SomeAnnotation::class.createInstance()
like image 123
Клаус Шварц Avatar answered Oct 24 '22 21:10

Клаус Шварц


This is the solution I might have found but feels like a hack to me and I would prefer to be able to solve it within the language. Anyway, for what is worth,it goes like this:

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
    }
}
like image 27
Claudiu Dumitrescu Avatar answered Oct 24 '22 20:10

Claudiu Dumitrescu