Support Kotlin annotation constructors in reflection

#KT-13106 In Progress
This commit is contained in:
Alexander Udalov
2016-09-14 19:52:57 +03:00
parent fb18e4bf4c
commit aeba124bdb
12 changed files with 344 additions and 14 deletions
@@ -0,0 +1,12 @@
// WITH_REFLECT
import kotlin.reflect.KClass
import kotlin.test.assertEquals
annotation class Anno(val klasses: Array<KClass<*>> = arrayOf(String::class, Int::class))
fun box(): String {
val anno = Anno::class.constructors.single().callBy(emptyMap())
assertEquals(listOf(String::class, Int::class), (anno.klasses as Array<KClass<*>>).toList() /* TODO: KT-9453 */)
return "OK"
}
@@ -0,0 +1,50 @@
// WITH_REFLECT
import kotlin.reflect.KClass
import kotlin.reflect.primaryConstructor
import kotlin.test.assertEquals
import kotlin.test.assertFails
annotation class NoParams
annotation class OneDefault(val s: String = "OK")
annotation class OneNonDefault(val s: String)
annotation class TwoParamsOneDefault(val s: String, val x: Int = 42)
annotation class TwoParamsOneDefaultKClass(val string: String, val klass: KClass<*> = Number::class)
annotation class TwoNonDefaults(val string: String, val klass: KClass<*>)
inline fun <reified T : Annotation> create(args: Map<String, Any?>): T {
val ctor = T::class.constructors.single()
return ctor.callBy(args.mapKeys { entry -> ctor.parameters.single { it.name == entry.key } })
}
inline fun <reified T : Annotation> create(): T = create(emptyMap())
fun box(): String {
create<NoParams>()
val t1 = create<OneDefault>()
assertEquals("OK", t1.s)
assertFails { create<OneDefault>(mapOf("s" to 42)) }
val t2 = create<OneNonDefault>(mapOf("s" to "OK"))
assertEquals("OK", t2.s)
assertFails { create<OneNonDefault>() }
val t3 = create<TwoParamsOneDefault>(mapOf("s" to "OK"))
assertEquals("OK", t3.s)
assertEquals(42, t3.x)
val t4 = create<TwoParamsOneDefault>(mapOf("s" to "OK", "x" to 239))
assertEquals(239, t4.x)
assertFails { create<TwoParamsOneDefault>(mapOf("s" to "Fail", "x" to "Fail")) }
val t5 = create<TwoParamsOneDefaultKClass>(mapOf("string" to "OK"))
assertEquals(Number::class, t5.klass as KClass<*> /* TODO: KT-9453 */)
assertFails("KClass (not Class) instances should be passed as arguments") {
create<TwoNonDefaults>(mapOf("klass" to String::class.java, "string" to "Fail"))
}
val t6 = create<TwoNonDefaults>(mapOf("klass" to String::class, "string" to "OK"))
return t6.string
}
@@ -0,0 +1,35 @@
// WITH_REFLECT
import kotlin.reflect.KClass
import kotlin.reflect.primaryConstructor
import kotlin.test.assertEquals
import kotlin.test.assertFails
annotation class NoParams
annotation class OneDefault(val s: String = "Fail")
annotation class TwoNonDefaults(val string: String, val klass: KClass<*>)
inline fun <reified T : Annotation> create(vararg args: Any?): T =
T::class.constructors.single().call(*args)
fun box(): String {
create<NoParams>()
assertFails { create<NoParams>("Fail") }
assertFails { create<OneDefault>() }
assertFails { create<OneDefault>(42) }
val o = create<OneDefault>("OK")
assertEquals("OK", o.s)
assertFails("call() should fail because arguments were passed in an incorrect order") {
create<TwoNonDefaults>(Any::class, "Fail")
}
assertFails("call() should fail because KClass (not Class) instances should be passed as arguments") {
create<TwoNonDefaults>("Fail", Any::class.java)
}
val k = create<TwoNonDefaults>("OK", Int::class)
assertEquals(Int::class, k.klass as KClass<*> /* TODO: KT-9453 */)
return k.string
}